2013-08-02 20 views
14

SQL Server 2008R2には次のソースと目的のテーブルがあります。 TSQLでどのようにピボットを行ってソースからデスティネーションに到達することができますか?SQL Server 1つの列に基づいて複数の列をピボットする

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 

EMPINDEXは何とかピボットに役立つことを期待。

+0

ピボットはmsaccessのトランスフォームとも呼ばれます。あなたの質問は、結果のセルにテキスト(整数ではありません)がある点で独特です。集計関数がまだ適用されていなければなりません。この場合MIN()は、テキスト値が1つだけであっても、Text値を正しく処理する必要があります。 – hamish

答えて

23

SQL Serverを使用しているので、行を列に変換できるいくつかの方法があります。あなたは、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; 

SQL Fiddle with Demoを参照してください。

あなたが結果を得るために、ピボット機能を使用したい場合は、私はあなたが最初の複数の行を持つことになります列empStateempStDateempEndDateをアンピボット最初に推薦します。

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

参照Demo:あなたはコードがされるデータを変換するには、Apply UNPIVOT機能やCROSSを使用することができます。データがピボットを解除したら、最終的なコードがなりますので、あなたはPIVOT機能を適用することができます。

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を参照してください。バージョン上記

Thのあなたがempindexの数が限られている、そうでない場合ならば、あなたは、動的SQLを使用することができます偉大な動作します:

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; 

参照SQL Fiddle with Demo

あなたは挿入するには、これらのクエリを使用することができますDestTblに、またはこの形式でデータを格納する代わりに、目的の結果を取得するためのクエリが表示されます。

これらのクエリは、形式でデータを置く:

| 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

私はあなたの努力に感謝します。私の問題も解決します。ありがとう@bluefeet –

+0

私は多くの前に使用されたFOR XMLを見てきました。しかし、kudosと* thumbsup *を最高の使い方で使用しています:PIVOTのSTUFF QUOTENAMEとNVARCHAR(MAX):MSACCESSはこのTRANSFORMを呼び出しますSQLサーバーには決してしなかった) – hamish

-1

うわーこれは私が想像よりも複雑でしたが、私はそれは偉大な仕事になりました!ありがとう。これは私の最終版でした。 TextKeyには列に変換するデータが含まれ、TextValueには各セルの内部で終わる値が入ります。

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) 
関連する問題