178 votes

TSQL Pivot sans fonction d'agrégation

J'ai une table comme celle-ci...

CustomerID   DBColumnName   Data
--------------------------------------
1            FirstName      Joe
1            MiddleName     S
1            LastName       Smith
1            Date           12/12/2009
2            FirstName      Sam
2            MiddleName     S
2            LastName       Freddrick
2            Date           1/12/2009
3            FirstName      Jaime
3            MiddleName     S
3            LastName       Carol
3            Date           12/1/2009

Et je veux ça...

Est-ce possible en utilisant PIVOT ?

CustomerID  FirstName   MiddleName          LastName        Date
----------------------------------------------------------------------
1           Joe             S               Smith           12/12/2009
2           Sam             S               Freddrick       1/12/2009
3           Jaime           S               Carol           12/1/2009

216voto

Charles Bretana Points 59899

oui, mais pourquoi ! !!

   Select CustomerID,
     Min(Case DBColumnName When 'FirstName' Then Data End) FirstName,
     Min(Case DBColumnName When 'MiddleName' Then Data End) MiddleName,
     Min(Case DBColumnName When 'LastName' Then Data End) LastName,
     Min(Case DBColumnName When 'Date' Then Data End) Date
   From table
   Group By CustomerId

2 votes

^^ Cela a marché pour moi. PIVOT n'est pas efficace pour les valeurs non numériques.

6 votes

C'est une excellente alternative. J'utilisais Pivot dans ma requête, puis je suis passé à celle-ci et j'ai regardé le plan d'exécution pour l'exécution des deux ensemble. Cette approche a coûté 8% et l'approche Pivot a pris 92% !

2 votes

CharlesBretana, tu es génial ! Vous avez sauvé mon âme ! ) C'est la meilleure solution. Merci !

129voto

gbn Points 197263

Vous pouvez utiliser l'agrégat MAX, cela fonctionnera toujours. MAX d'une valeur = cette valeur

Dans ce cas, vous pourriez aussi faire une auto-jonction 5 fois sur customerid, filtrer par dbColumnName par référence de table. Cela peut fonctionner mieux.

1 votes

Cela ne fonctionnera pas si vous avez deux clients avec le même prénom.

1 votes

Ça va marcher. N'oubliez pas que DBColumnName est une métadonnée - vous filtrez littéralement par "CustomerID = 1 AND DBColumnName = 'FirstName'". Bien sûr, cela ne fonctionne pas si vous avez plusieurs lignes FirstName pour un CustomerID donné, mais si vous créez vos tables correctement, CustomerID et DBColumnName font tous deux partie de votre clé primaire...

11 votes

Un exemple de code/mocking aurait été très bien et aurait rendu cette réponse parfaitement complète.

13voto

ctrlShiftBryan Points 5620

Ok, désolé pour cette mauvaise question. gbn m'a mis sur la bonne voie. C'est ce que je cherchais dans une réponse.

SELECT [FirstName], [MiddleName], [LastName], [Date] 
FROM #temp 
PIVOT
(   MIN([Data]) 
    FOR [DBColumnName] IN ([FirstName], [MiddleName], [LastName], [Date]) 
)AS p

Ensuite, j'ai dû utiliser une déclaration while et construire la déclaration ci-dessus en tant que varchar et utiliser le sql dynmaic.

En utilisant quelque chose comme ceci

SET @fullsql = @fullsql + 'SELECT ' + REPLACE(REPLACE(@fulltext,'(',''),')','')
SET @fullsql = @fullsql + 'FROM #temp '
SET @fullsql = @fullsql + 'PIVOT'
SET @fullsql = @fullsql + '('
SET @fullsql = @fullsql + ' MIN([Data])'
SET @fullsql = @fullsql + ' FOR [DBColumnName] IN '+@fulltext
SET @fullsql = @fullsql + ')'
SET @fullsql = @fullsql + 'AS p'

EXEC (@fullsql)

Je dois construire @fulltext en utilisant une boucle while et en sélectionnant les noms de colonnes distinctes dans la table. Merci pour les réponses.

9voto

shahkalpesh Points 21553
SELECT
main.CustomerID,
f.Data AS FirstName,
m.Data AS MiddleName,
l.Data AS LastName,
d.Data AS Date
FROM table main
INNER JOIN table f on f.CustomerID = main.CustomerID
INNER JOIN table m on m.CustomerID = main.CustomerID
INNER JOIN table l on l.CustomerID = main.CustomerID
INNER JOIN table d on d.CustomerID = main.CustomerID
WHERE f.DBColumnName = 'FirstName' 
AND m.DBColumnName = 'MiddleName' 
AND l.DBColumnName = 'LastName' 
AND d.DBColumnName = 'Date' 

Edit : J'ai écrit ceci sans éditeur et je n'ai pas exécuté le SQL. J'espère que vous comprenez l'idée.

9voto

bielawski Points 34

L'OP n'avait pas réellement besoin de pivoter sans agregation mais pour ceux qui viennent ici pour savoir comment voir :

requête cte paramétrée en sql

La réponse à cette question implique une situation où un pivot sans agrégation est nécessaire. Un exemple de réalisation fait donc partie de la solution.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X