SQL Server: comment faire pivoter où les nouvelles colonnes ont plusieurs valeurs uniques

En utilisant cette table:

| CUST | PRODUCT | QTY | SMALLEST | ----------------------------------- | E | 1600 | 2 | 1 | | F | 1600 | 6 | 9 | | G | 1600 | 1 | 8 | 

Je veux le faire pivoter pour qu'il ressemble à ceci:

 | E | F | G | ------------------------------ | 1600 | 1600 | 1600 | | 2 | 6 | 1 | | 1 | 9 | 8 | 

Je sais comment faire avec une rangée unique. Si je n'ai que QTY ou que j'ai le plus petit, cela fonctionne bien avec cette requête par exemple:

Question

 SELECT E, F, G FROM ( SELECT CUST, PRODUCT, QTY FROM Product) up PIVOT (SUM(QTY) FOR CUST IN (E,F,G)) AS pvt 

Sortie

 | E | F | G | ------------- | 2 | 6 | 1 | 

Mais, si j'ajoute une autre colonne à la concoction dans une autre requête, j'obtiens ce bordel:

Question

 SELECT E, F, G FROM ( SELECT CUST, PRODUCT, QTY, SMALLEST FROM Product) up PIVOT (SUM(QTY) FOR CUST IN (E,F,G)) AS pvt 

Sortie

 | E | F | G | ---------------------------- | 2 | (null) | (null) | | (null) | (null) | 1 | | (null) | 6 | (null) | 

Et c'est facile de voir pourquoi quand je change la requête:

Question

 SELECT product,smallest, E, F, G FROM ( SELECT CUST, PRODUCT, QTY, SMALLEST FROM Product) up PIVOT (SUM(QTY) FOR CUST IN (E,F,G)) AS pvt 

Sortie

 | PRODUCT | SMALLEST | E | F | G | ------------------------------------------------- | 1600 | 1 | 2 | (null) | (null) | | 1600 | 8 | (null) | (null) | 1 | | 1600 | 9 | (null) | 6 | (null) | 

Le motif devient évident. Il s'agit de find où il y a 1600 et 1 il y a une valeur E: 2, où il y a 1600 et 8 il y a une valeur F 6, etc.

J'ai le problème, mais je n'ai aucune idée de comment le réparer. Quelqu'un peut-il m'aider dans ma quête futile?

SQL Fiddle

Vraiment, vous voulez un UNPIVOT pour prendre soin des multiples colonnes, puis un PIVOT pour get vos données. Ma façon préférée de faire UNPIVOT est d'utiliser CROSS APPLY , mais vous pouvez le faire comme vous voulez. Comme tel.

 SELECT E, F, G FROM ( SELECT CUST, ColumnName, Value FROM Product CROSS APPLY ( VALUES ('PRODUCT', PRODUCT), ('QTY', QTY), ('SMALLEST',SMALLEST)) UnPivoted(ColumnName, Value)) up PIVOT (SUM(VALUE) FOR CUST IN (E,F,G)) AS pvt 

Et bien sûr, si vous voulez voir de quelle colonne proviennent les valeurs:

 SELECT ColumnName, E, F, G FROM ( SELECT CUST, ColumnName, Value FROM Product CROSS APPLY ( VALUES ('PRODUCT', PRODUCT), ('QTY', QTY), ('SMALLEST',SMALLEST)) UnPivoted(ColumnName, Value)) up PIVOT (SUM(VALUE) FOR CUST IN (E,F,G)) AS pvt 

MODIFIER:

Voici une solution pour plusieurs types. Fondamentalement, vous devez avoir plusieurs requêtes, une pour chaque type de données. Entre autres choses, vous avez un SUM dans votre requête numérique qui ne fonctionnera pas sur les colonnes varchar. Votre sortie doit également être tous les mêmes. Cela signifie que vous devez convertir n'importe quelle colonne numérique ou date en varchar.

 SELECT ColumnName, CAST(E AS varchar(30)) E, CAST(F AS varchar(30)) F, CAST(G AS varchar(30)) G FROM ( SELECT CUST, ColumnName, Value FROM Product CROSS APPLY ( VALUES ('PRODUCT', PRODUCT), ('QTY', QTY), ('SMALLEST',SMALLEST)) UnPivoted(ColumnName, Value)) up PIVOT (SUM(VALUE) FOR CUST IN (E,F,G)) AS pvt UNION ALL SELECT ColumnName, E, F, G FROM ( SELECT CUST, ColumnName, Value FROM Product CROSS APPLY ( VALUES ('CharColA', CharColA), ('CharColB', CharColB)) UnPivoted(ColumnName, Value)) up PIVOT (MIN(VALUE) FOR CUST IN (E,F,G)) AS pvt 

Vous pouvez le faire avec CROSS-APPLY et PIVOT :

 SELECT E,F,G FROM ( SELECT Cust,col,value FROM #Product CROSS APPLY ( VALUES ('E', Product),('F', QTY),('G', SMALLEST) ) C (COL, VALUE) ) SRC PIVOT ( MAX(VALUE) FOR CUST IN (E,F,G) ) PIV 

Démo: SQL Fiddle