2013-08-02 17 views
14

Ho le seguenti tabelle di origine e destinazione in SQL Server 2008R2. Come posso fare pivot (s) in TSQL per arrivare alla destinazione dalla fonte.SQL Server Ruota più colonne in base a una colonna

SourceTbl

empId empIndex empState empStDate empEndDate 
======================================================== 
10  1   AL   1/1/2012  12/1/2012 
10  2   FL   2/1/2012  2/1/2013 
15  1   FL   3/20/2012 1/1/2099 

DestTbl

empId empState1 empState1StDate empState1EndDt empState2 empState2StDate empState2EndDt 
========================================================================================================= 
10  AL   1/1/2012   12/1/2012   FL   2/1/2012   2/1/2013 
15  FL   3/20/2012   1/1/2099   NULL  NULL    NULL 

Sperando che l'empIndex in qualche modo aiutare nella perno.

+0

pivot è anche noto come trasformazione in msaccess. la tua domanda è unica in quanto ha anche testo (non numeri interi) nelle celle risultanti. la funzione di aggregazione deve ancora essere applicata, in questo caso MIN() dovrebbe fare bene sui valori di Testo, anche quando c'è solo 1 valore di testo. – hamish

risposta

23

Poiché si utilizza SQL Server, è possibile convertire le righe in colonne in diversi modi. È possibile utilizzare una funzione di aggregazione con un'espressione CASE:

select empid, 
    max(case when empindex = 1 then empstate end) empState1, 
    max(case when empindex = 1 then empStDate end) empStDate1, 
    max(case when empindex = 1 then empEndDate end) empEndDate1, 
    max(case when empindex = 2 then empstate end) empState2, 
    max(case when empindex = 2 then empStDate end) empStDate2, 
    max(case when empindex = 2 then empEndDate end) empEndDate2 
from sourcetbl 
group by empid; 

Vedi SQL Fiddle with Demo.

Se si desidera utilizzare la funzione pivot per ottenere il risultato, allora vi consiglio prima unpivoting le colonne empState, empStDate e empEndDate in modo da avere più righe prima. È possibile utilizzare la funzione UNPIVOT o CROSS Applica per convertire i dati il ​​codice sarà:

select empid, col+cast(empindex as varchar(10)) col, value 
from sourcetbl 
cross apply 
(
    select 'empstate', empstate union all 
    select 'empstdate', convert(varchar(10), empstdate, 120) union all 
    select 'empenddate', convert(varchar(10), empenddate, 120) 
) c (col, value); 

Vedi Demo. Una volta che i dati sono pivot, allora si può applicare la funzione pivot in modo che il codice finale sarà:

select empid, 
    empState1, empStDate1, empEndDate1, 
    empState2, empStDate2, empEndDate2 
from 
(
    select empid, col+cast(empindex as varchar(10)) col, value 
    from sourcetbl 
    cross apply 
    (
    select 'empstate', empstate union all 
    select 'empstdate', convert(varchar(10), empstdate, 120) union all 
    select 'empenddate', convert(varchar(10), empenddate, 120) 
) c (col, value) 
) d 
pivot 
(
    max(value) 
    for col in (empState1, empStDate1, empEndDate1, 
       empState2, empStDate2, empEndDate2) 
) piv; 

Vedi SQL Fiddle with Demo.

Th sopra versioni funzionerà grande se si dispone di un numero limitato di empindex, ma se poi non è possibile utilizzare SQL dinamico:

DECLARE @cols AS NVARCHAR(MAX), 
    @query AS NVARCHAR(MAX) 

select @cols = STUFF((SELECT ',' + QUOTENAME(col+cast(empindex as varchar(10))) 
        from SourceTbl 
        cross apply 
        (
         select 'empstate', 1 union all 
         select 'empstdate', 2 union all 
         select 'empenddate', 3 
        ) c (col, so) 
        group by col, so, empindex 
        order by empindex, so 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT empid,' + @cols + ' 
      from 
      (
       select empid, col+cast(empindex as varchar(10)) col, value 
       from sourcetbl 
       cross apply 
       (
        select ''empstate'', empstate union all 
        select ''empstdate'', convert(varchar(10), empstdate, 120) union all 
        select ''empenddate'', convert(varchar(10), empenddate, 120) 
       ) c (col, value) 
      ) x 
      pivot 
      (
       max(value) 
       for col in (' + @cols + ') 
      ) p ' 

execute sp_executesql @query; 

vedere SQL Fiddle with Demo

È possibile utilizzare queste query di INSERT INTO il tuo DestTbl, o invece di memorizzare i dati in questo formato, ora hai una query per ottenere il risultato desiderato.

Queste query inserire i dati nel formato:

| EMPID | EMPSTATE1 | EMPSTDATE1 | EMPENDDATE1 | EMPSTATE2 | EMPSTDATE2 | EMPENDDATE2 | 
--------------------------------------------------------------------------------------- 
| 10 |  AL | 2012-01-01 | 2012-12-01 |  FL | 2012-02-01 | 2013-02-01 | 
| 15 |  FL | 2012-03-20 | 2099-01-01 | (null) |  (null) |  (null) | 
+0

Apprezzo il tuo sforzo. Risolve anche il mio problema. Grazie mille @bluefeet –

+0

Ho visto FOR XML usato molto prima .. ma kudos e * thumbsup * per il miglior uso di: STUFF QUOTENAME e NVARCHAR (MAX) in un PIVOT :) MSACCESS chiama questo TRANSFORM (non so perché quel comando mai fatto al server SQL) – hamish

-1

Wow questo è stato più complicato di quanto immaginassi, ma l'ho fatto a farlo funzionare grande! Grazie. Questa era la mia versione finale. TextKey contiene i dati che desideri trasformare in colonne e TextValue è il valore che finisce all'interno di ogni cella.

DECLARE @cols AS NVARCHAR(MAX), 
     @query AS NVARCHAR(MAX) 


select @cols = STUFF((SELECT distinct ', ' + QUOTENAME(TextKey) 
        from #SourceTbl 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT FromEntityID, DisplayName, ' + @cols + ' 
       FROM 
       (
        select FromEntityID, DisplayName, TextKey, TextValue 
        from #SourceTbl 
      ) x 
       pivot 
       (
        min(TextValue) 
        for TextKey in (' + @cols + ') 
      ) p 
       ORDER BY FromEntityID 
       ' 

execute(@query) 
Problemi correlati