Je m'excuse d'avoir soumis une autre question sur ce sujet, mais j'ai lu bon nombre des réponses à ce sujet et je n'arrive pas à le faire fonctionner pour moi.
J'ai trois tables que je dois rejoindre et extraire des informations. L'une des tables ne comporte que 3 colonnes et stocke les données verticalement. Je voudrais transposer ces données dans un format horizontal.
Les données ressembleront à ceci si je viens de rejoindre et de tirer:
SELECT
a.app_id,
b.field_id,
c.field_name,
b.field_value
FROM table1 a
JOIN table2 b ON a.app_id = b.app_id
JOIN table3 c ON b.field_id = c.field_id --(table3 is a lookup table for field names)
Résultat:
app_id | field_id | field_name | field_value
-----------------------------------------------------
1234 | 101 | First Name | Joe
1234 | 102 | Last Name | Smith
1234 | 105 | DOB | 10/15/72
1234 | 107 | Mailing Addr | PO BOX 1234
1234 | 110 | Zip | 12345
1239 | 101 | First Name | Bob
1239 | 102 | Last Name | Johnson
1239 | 105 | DOB | 12/01/78
1239 | 107 | Mailing Addr | 1234 N Star Ave
1239 | 110 | Zip | 12456
Au lieu de cela, je voudrais qu'il ressemble à ceci:
app_id | First Name | Last Name | DOB | Mailing Addr | Zip
--------------------------------------------------------------------------
1234 | Joe | Smith | 10/15/72 | PO BOX 1234 | 12345
1239 | Bob | Johnson | 12/01/78 | 1234 N Star Ave | 12456
Dans le passé, je me suis contenté de rechercher tous les field_id dont j'avais besoin dans mes données et j'ai créé des instructions CASE pour chacune. L'application que les utilisateurs utilisent contient des données pour plusieurs produits et chaque produit contient des champs différents. Compte tenu du nombre de produits pris en charge et du nombre de champs pour chaque produit (beaucoup, beaucoup plus que l'exemple de base que j'ai montré ci-dessus), il faut beaucoup de temps pour les rechercher et écrire d'énormes morceaux d'instructions CASE.
Je me demandais s'il y avait un code de triche pour atteindre ce dont j'ai besoin sans avoir à rechercher les field_ids et à écrire des choses. Je sais que la fonction PIVOT est probablement ce que je recherche, cependant, je n'arrive pas à la faire fonctionner correctement.
Vous pensez que vous pourriez aider?
Vous pouvez utiliser la fonction PIVOT pour convertir vos lignes de données en colonnes.
Votre requête d'origine peut être utilisée pour récupérer toutes les données, la seule modification que j'apporterais serait d'exclure la colonne b.field_id
car cela modifiera l'affichage final du résultat.
Si vous avez une liste connue de field_name
valeurs que vous souhaitez transformer en colonnes, vous pouvez alors coder en dur votre requête:
select app_id,
[First Name], [Last Name], [DOB],
[Mailing Addr], [Zip]
from
(
SELECT
a.app_id,
c.field_name,
b.field_value
FROM table1 a
INNER JOIN table2 b
ON a.app_id = b.app_id
INNER JOIN table3 c
ON b.field_id = c.field_id
) d
pivot
(
max(field_value)
for field_name in ([First Name], [Last Name], [DOB],
[Mailing Addr], [Zip])
) piv;
Voir SQL Fiddle with Demo .
Mais si vous voulez avoir un nombre inconnu de valeurs pour field_name
, vous devrez alors implémenter du SQL dynamique pour obtenir le résultat:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT ',' + QUOTENAME(Field_name)
from Table3
group by field_name, Field_id
order by Field_id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT app_id,' + @cols + '
from
(
SELECT
a.app_id,
c.field_name,
b.field_value
FROM table1 a
INNER JOIN table2 b
ON a.app_id = b.app_id
INNER JOIN table3 c
ON b.field_id = c.field_id
) x
pivot
(
max(field_value)
for field_name in (' + @cols + ')
) p '
execute sp_executesql @query;
Voir SQL Fiddle with Demo . Ces deux résultats donneront un résultat:
| APP_ID | FIRST NAME | LAST NAME | DOB | MAILING ADDR | Zip |
------------------------------------------------------------------------
| 1234 | Joe | Smith | 10/15/72 | PO Box 1234 | 12345 |
| 1239 | Bob | Johnson | 12/01/78 | 1234 N Star Ave | 12456 |
Essaye ça
SELECT
[app_id]
,MAX([First Name]) AS [First Name]
,MAX([Last Name]) AS [Last Name]
,MAX([DOB]) AS [DOB]
,MAX([Mailing Addr]) AS [Mailing Addr]
,MAX([Zip]) AS [Zip]
FROM Table1
PIVOT
(
MAX([field_value]) FOR [field_name] IN ([First Name],[Last Name],[DOB],[Mailing Addr],[Zip])
) T
GROUP BY [app_id]
la réponse de bluefeet était la bonne pour moi, mais j'avais besoin de distinct sur la liste des colonnes:
DECLARE @cols AS NVARCHAR(MAX),
@query AS NVARCHAR(MAX)
select @cols = STUFF((SELECT Distinct ',' + QUOTENAME(Field_name)
from Table3
group by field_name, Field_id
order by ',' + QUOTENAME(Field_name)
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)')
,1,1,'')
set @query = 'SELECT app_id,' + @cols + '
from
(
SELECT
a.app_id,
c.field_name,
b.field_value
FROM table1 a
INNER JOIN table2 b
ON a.app_id = b.app_id
INNER JOIN table3 c
ON b.field_id = c.field_id
) x
pivot
(
max(field_value)
for field_name in (' + @cols + ')
) p '
execute sp_executesql @query;
Utilisation de SQL Pivot
SELECT [Id], [FirstName], [LastName], [Email]
FROM
(
SELECT Id, Att_Id, Att_Value FROM VerticalTable
) as source
PIVOT
(
MAX(Att_Value) FOR Att_Id IN ([FirstName], [LastName], [Email])
) as target