web-dev-qa-db-fra.com

SQL Server 2008 Vertical data to Horizontal

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?

15
Fill in the Blank

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 |
30
Taryn

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]

DÉMO FIDDLE SQL

3
bvr

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;
0
ScottFoster1000

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
0
JIYAUL MUSTAPHA