Comment changer simplement de colonne avec des lignes en SQL? Y a-t-il une commande simple à transposer?
ie tourner ce résultat:
Paul | John | Tim | Eric
Red 1 5 1 3
Green 8 4 3 5
Blue 2 2 9 1
dans ceci:
Red | Green | Blue
Paul 1 8 2
John 5 4 2
Tim 1 3 9
Eric 3 5 1
PIVOT
semble trop complexe pour ce scénario.
sql
sql-server
tsql
pivot
Edezzie
la source
la source
Réponses:
Il existe plusieurs manières de transformer ces données. Dans votre article d'origine, vous avez déclaré que cela
PIVOT
semble trop complexe pour ce scénario, mais cela peut être appliqué très facilement à l'aide des fonctionsUNPIVOT
etPIVOT
de SQL Server.Cependant, si vous n'avez pas accès à ces fonctions, cela peut être répliqué à l'aide de
UNION ALL
toUNPIVOT
, puis d'une fonction d'agrégation avec uneCASE
instruction toPIVOT
:Créer une table:
Version Union All, Agrégat et CASE:
Voir SQL Fiddle avec démo
Le
UNION ALL
exécute laUNPIVOT
des données en transformant les colonnesPaul, John, Tim, Eric
en lignes séparées. Ensuite, vous appliquez la fonction d'agrégationsum()
avec l'case
instruction pour obtenir les nouvelles colonnes pour chacuncolor
.Unpivot et la version statique du pivot:
Les fonctions
UNPIVOT
etPIVOT
du serveur SQL rendent cette transformation beaucoup plus facile. Si vous connaissez toutes les valeurs que vous souhaitez transformer, vous pouvez les coder en dur dans une version statique pour obtenir le résultat:Voir SQL Fiddle avec démo
La requête interne avec le
UNPIVOT
exécute la même fonction que leUNION ALL
. Il prend la liste des colonnes et la transforme en lignes,PIVOT
puis effectue la transformation finale en colonnes.Version du pivot dynamique:
Si vous avez un nombre inconnu de colonnes (
Paul, John, Tim, Eric
dans votre exemple), puis un nombre inconnu de couleurs à transformer, vous pouvez utiliser SQL dynamique pour générer la liste versUNPIVOT
et ensuitePIVOT
:Voir SQL Fiddle avec démo
La version dynamique interroge les deux
yourtable
, puis lasys.columns
table pour générer la liste des éléments versUNPIVOT
etPIVOT
. Ceci est ensuite ajouté à une chaîne de requête à exécuter. Le plus de la version dynamique est si vous avez une liste changeante decolors
et / ounames
cela générera la liste au moment de l'exécution.Les trois requêtes produiront le même résultat:
la source
Cela nécessite normalement que vous connaissiez au préalable TOUTES les étiquettes de colonne ET de ligne. Comme vous pouvez le voir dans la requête ci-dessous, les étiquettes sont toutes répertoriées dans leur intégralité dans les opérations UNPIVOT et (re) PIVOT.
Configuration du schéma MS SQL Server 2012 :
Requête 1 :
Résultats :
Notes complémentaires:
la source
Je voudrais souligner quelques autres solutions pour transposer des colonnes et des lignes en SQL.
Le premier est - en utilisant CURSOR. Bien que le consensus général dans la communauté professionnelle soit de rester à l'écart des curseurs SQL Server, il existe encore des cas dans lesquels l'utilisation de curseurs est recommandée. Quoi qu'il en soit, les curseurs nous présentent une autre option pour transposer les lignes en colonnes.
Expansion verticale
Semblable au PIVOT, le curseur a la capacité dynamique d'ajouter plus de lignes à mesure que votre ensemble de données se développe pour inclure plus de numéros de stratégie.
Expansion horizontale
Contrairement au PIVOT, le curseur excelle dans ce domaine car il est capable de s'étendre pour inclure le document nouvellement ajouté, sans modifier le script.
Répartition des performances
La principale limitation de la transposition de lignes en colonnes à l'aide de CURSOR est un inconvénient lié à l'utilisation des curseurs en général - ils ont un coût de performance significatif. Cela est dû au fait que le curseur génère une requête distincte pour chaque opération FETCH NEXT.
Une autre solution de transposition de lignes en colonnes consiste à utiliser XML.
La solution XML pour transposer des lignes en colonnes est fondamentalement une version optimale du PIVOT en ce qu'elle résout la limitation dynamique des colonnes.
La version XML du script résout cette limitation en utilisant une combinaison de chemin XML, de T-SQL dynamique et de certaines fonctions intégrées (c'est-à-dire STUFF, QUOTENAME).
Expansion verticale
À l'instar du PIVOT et du curseur, les stratégies nouvellement ajoutées peuvent être récupérées dans la version XML du script sans modifier le script d'origine.
Expansion horizontale
Contrairement au PIVOT, les documents nouvellement ajoutés peuvent être affichés sans modifier le script.
Répartition des performances
En termes d'E / S, les statistiques de la version XML du script sont presque similaires à celles du PIVOT - la seule différence est que le XML a un deuxième scan de la table dtTranspose mais cette fois à partir d'un cache logique de lecture de données.
Vous pouvez trouver plus d'informations sur ces solutions (y compris des exemples réels de T-SQL) dans cet article: https://www.sqlshack.com/multiple-options-to-transposing-rows-into-columns/
la source
Sur la base de cette solution de bluefeet, voici une procédure stockée qui utilise SQL dynamique pour générer la table transposée. Il faut que tous les champs soient numériques à l'exception de la colonne transposée (la colonne qui sera l'en-tête dans le tableau résultant):
Vous pouvez le tester avec le tableau fourni avec cette commande:
la source
Je fais d'
UnPivot
abord et stocke les résultats dansCTE
et utilise leCTE
enPivot
fonctionnement.Démo
la source
En ajoutant à la réponse formidable de @Paco Zarate ci-dessus, si vous souhaitez transposer un tableau qui a plusieurs types de colonnes, ajoutez-le à la fin de la ligne 39, de sorte qu'il ne transpose que les
int
colonnes:Voici la requête complète en cours de modification:
Pour en trouver d'autres
system_type_id
, exécutez ceci:la source
J'aime partager le code que j'utilise pour transposer un texte fractionné basé sur la réponse + bluefeet. Dans cette approche, je suis implémenté en tant que procédure dans MS SQL 2005
Je mélange cette solution avec les informations sur la façon de classer les lignes sans ordre par ( SQLAuthority.com ) et la fonction de fractionnement sur MSDN ( social.msdn.microsoft.com )
Lorsque vous exécutez la prodecure
vous obtenez le résultat suivant
la source
De cette façon, convertissez toutes les données des fichiers (colonnes) dans le tableau en enregistrement (ligne).
la source
J'ai pu utiliser la solution de Paco Zarate et cela fonctionne à merveille. J'ai dû ajouter une ligne ("SET ANSI_WARNINGS ON"), mais cela peut être quelque chose d'unique à la façon dont je l'ai utilisé ou appelé. Il y a un problème avec mon utilisation et j'espère que quelqu'un pourra m'aider:
La solution fonctionne uniquement avec une table SQL réelle. Je l'ai essayé avec une table temporaire et aussi une table en mémoire (déclarée) mais cela ne fonctionne pas avec ceux-ci. Donc, dans mon code d'appel, je crée une table sur ma base de données SQL, puis j'appelle SQLTranspose. Encore une fois, cela fonctionne très bien. C'est juste ce que je veux. Voici mon problème:
Pour que la solution globale soit vraiment dynamique, je dois créer cette table où je stocke temporairement les informations préparées que j'envoie à SQLTranspose "à la volée", puis supprimer cette table une fois que SQLTranspose est appelé. La suppression de la table pose un problème avec mon plan de mise en œuvre ultime. Le code doit s'exécuter à partir d'une application utilisateur final (un bouton sur un formulaire / menu Microsoft Access). Lorsque j'utilise ce processus SQL (créer une table SQL, appeler SQLTranspose, supprimer une table SQL), l'application utilisateur final rencontre une erreur car le compte SQL utilisé n'a pas le droit de supprimer une table.
Je pense donc qu'il y a quelques solutions possibles:
Trouvez un moyen de faire fonctionner SQLTranspose avec une table temporaire ou une variable de table déclarée.
Trouvez une autre méthode pour la transposition des lignes et des colonnes qui ne nécessite pas une table SQL réelle.
Trouvez une méthode appropriée pour permettre au compte SQL utilisé par mes utilisateurs finaux de supprimer une table. C'est un seul compte SQL partagé codé dans mon application Access. Il semble que l'autorisation soit un privilège de type dbo qui ne peut pas être accordé.
Je reconnais que certains de ces éléments peuvent justifier un autre fil et une question distincts. Cependant, comme il y a une possibilité qu'une solution puisse être simplement une manière différente de faire la transposition des lignes et des colonnes, je ferai mon premier message ici dans ce fil.
EDIT: J'ai également remplacé sum (valeur) par max (valeur) dans la 6ème ligne à partir de la fin, comme Paco l'a suggéré.
ÉDITER:
J'ai trouvé quelque chose qui fonctionne pour moi. Je ne sais pas si c'est la meilleure réponse ou non.
J'ai un compte d'utilisateur en lecture seule qui est utilisé pour exécuter des procédures strictes et donc générer des résultats de rapport à partir d'une base de données. Étant donné que la fonction SQLTranspose que j'ai créée ne fonctionnera qu'avec une table "légitime" (pas une table déclarée ni une table temporaire), j'ai dû trouver un moyen pour un compte utilisateur en lecture seule de créer (puis de supprimer plus tard) une table .
J'ai pensé que pour mes besoins, il était normal que le compte utilisateur soit autorisé à créer une table. L'utilisateur n'a toujours pas pu supprimer la table. Ma solution était de créer un schéma où le compte utilisateur est autorisé. Ensuite, chaque fois que je crée, utilise ou supprime cette table, faites-la référence avec le schéma spécifié.
J'ai d'abord émis cette commande à partir d'un compte 'sa' ou 'sysadmin': CREATE SCHEMA ro AUTHORIZATION
À chaque fois que je me réfère à ma table "tmpoutput", je le spécifie comme cet exemple:
déposer la table ro.tmpoutput
la source