2013-08-02 16 views
14

Ich habe folgende Quell- und Zieltabellen in SQL Server 2008R2. Wie kann ich in TSQL pivotieren, um von der Quelle zum Ziel zu gelangen?SQL Server Pivot mehrere Spalten basierend auf einer Spalte

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 

der Hoffnung, dass die EMPINDEX irgendwie in der Pivot helfen.

+0

Pivot wird auch als Transformation in msaccess bezeichnet. Ihre Frage ist insofern einzigartig, als sie auch Text (keine ganzen Zahlen) in den resultierenden Zellen enthält. Die Aggregatfunktion muss immer noch angewendet werden, in diesem Fall sollte MIN() für Textwerte ausreichen, auch wenn nur ein Textwert vorhanden ist. – hamish

Antwort

23

Da Sie SQL Server verwenden, gibt es verschiedene Möglichkeiten, die Zeilen in Spalten umzuwandeln. Sie können eine Aggregatfunktion mit einem CASE-Ausdruck verwenden:

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; 

Siehe SQL Fiddle with Demo.

Wenn Sie die Pivot-Funktion erhalten Sie das Ergebnis verwenden wollen, dann würde ich empfehlen, zuerst unpivoting die Spalten empState, empStDate und empEndDate so werden Sie zunächst mehrere Zeilen haben. Sie können die UNPIVOT Funktion oder CROSS APPLY verwenden, um die Daten zu konvertieren wird der Code sein:

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); 

Siehe Demo. Sobald die Daten nicht verschwenkten ist, dann können Sie die Pivot-Funktion anwenden, so wird der endgültige Code sein:

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; 

SQL Fiddle with Demo See.

Th oben genannten Versionen wird groß, wenn Sie eine begrenzte Anzahl von empindex haben, aber wenn nicht, dann können Sie die dynamische SQL verwenden:

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; 

Siehe SQL Fiddle with Demo

Sie können diese Abfragen verwenden, um INSERT INTO DestTbl, oder anstatt die Daten in diesem Format zu speichern, haben Sie jetzt eine Abfrage, um das gewünschte Ergebnis zu erhalten.

Diese Abfragen stellen die Daten im Format:

| 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

Ich schätze Ihre Bemühungen. Es löst mein Problem auch. Vielen Dank @bluefeet –

+0

Ich habe gesehen, dass FOR XML viel zuvor verwendet .. aber kudos und * thumbsup * für die beste Verwendung von: STUFF QUOTENAME und NVARCHAR (MAX) in einem PIVOT :) MSACCESS ruft diese TRANSFORM (nicht sicher, warum dieser Befehl hat es nie zum SQL Server geschafft) – hamish

-1

Wow das war komplizierter als ich dachte, aber ich habe es sehr gut zu funktionieren! Vielen Dank. Das war meine endgültige Version. Der TextKey enthält die Daten, die in Spalten umgewandelt werden sollen, und der TextValue ist der Wert, der in jeder Zelle endet.

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) 
Verwandte Themen