2013-08-08 13 views
13

Mi scuso per aver presentato un'altra domanda su questo argomento, ma ho letto molte delle risposte e non riesco a farlo funzionare correttamente.SQL Server 2008 Dati verticali su orizzontale

Ho tre tabelle che ho bisogno di unire e tirare informazioni su. Una delle tabelle è a sole 3 colonne e memorizza i dati verticalmente. Vorrei trasporre quei dati in un formato orizzontale.

I dati sarà simile a questo se ho appena unisco e tiro:

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) 

Risultato:

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 

Invece, mi piacerebbe assomigliare a questo:

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 

In passato, mi sono limitato a cercare tutti i field_id di cui avevo bisogno nei miei dati e ho creato le dichiarazioni CASE per ognuno di essi. L'app utilizzata dagli utenti contiene dati per più prodotti e ogni prodotto contiene campi diversi. Considerando il numero di prodotti supportati e il numero di campi per ciascun prodotto (molti, molti di più rispetto all'esempio di base che ho mostrato sopra) ci vuole molto tempo per cercarli e scrivere enormi blocchi di istruzioni CASE.

Mi chiedevo se ci fosse un codice cheat là fuori per ottenere ciò di cui ho bisogno senza dover cercare le field_ids e scrivere le cose. So che la funzione PIVOT è probabilmente quello che sto cercando, tuttavia, non riesco a farlo funzionare correttamente.

Pensa che potreste dare una mano?

risposta

29

È possibile utilizzare la funzione PIVOT per convertire i file di dati in colonne.

La query originale può essere utilizzata per recuperare tutti i dati, l'unica modifica che farei sarebbe escludere la colonna b.field_id poiché ciò altererebbe la visualizzazione finale del risultato.

Se si dispone di un elenco noto di field_name valori che si desidera trasformare in colonne, allora si può codificare la query:

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; 

Vedi SQL Fiddle with Demo.

Ma se avete intenzione di avere un numero imprecisato di valori per field_name, allora si avrà bisogno di implementare SQL dinamico per ottenere il risultato:

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; 

Vedi . Entrambi questi questo darà un risultato: risposta

| 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 | 
+4

Questo è esattamente quello che mi serviva.Non ho il rappresentante per revocarti, ma se qualcun altro qui fuori lo vede, per favore proteggi per me! –

3

Prova questa

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] 

SQL FIDDLE DEMO

0

di bluefeet era quella giusta per me, ma avevo bisogno distinta nella lista della colonna:

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; 
Problemi correlati