2013-04-10 18 views
191

まあ、私は本当に密集していると思います。私はMSのピボットテーブル上のものを読んで、私はまだこれを正しい得る問題があります。私はこの食べ物を食べて寝るように見えるあなたの人たちを見てきました。だから私はサインアップして質問しました。SQL Serverの「Pivot」を使用して列を列に変換する

作成中のテンポラリテーブルがあります。カラム1はストア番号、カラム2は週番号、最後はカラム3はあるタイプの合計です。また、週番号は動的で、店舗番号は静的です。

Store  Week  xCount 
------- ----  ------ 
102  1  96 
101  1  138 
105  1  37 
109  1  59 
101  2  282 
102  2  212 
105  2  78 
109  2  97 
105  3  60 
102  3  123 
101  3  220 
109  3  87 

私はそれがこのように、ピボットテーブルとして出てくるしたいと思います:

Store  1   2   3  4  5  6.... 
----- 
101  138  282  220 
102   96  212  123 
105   37   
109 

店舗番号上部に側と週ダウン。

ありがとうございました。

+0

は、コードの再フォーマット用のマークをありがとうございました。私はそれが分かったと思った、私はdidntを推測する。 :-) – Jeff

+1

それは私のカップルがかかった! :) –

+0

[SQL Server動的PIVOTクエリの可能な複製?](http://stackoverflow.com/questions/10404348/sql-server-dynamic-pivot-query) – RichardTheKiwi

答えて

245

SQL Server 2005以降を使用している場合は、PIVOT関数を使用して、データを行から列に変換できます。

週が不明な場合は動的SQLを使用する必要がありますが、最初はハードコードされたバージョンを使用して正しいコードを確認する方が簡単です。ここ

まずアップは、いくつかの簡単なテーブル定義とデータを使用するためのものです:

CREATE TABLE #yt 
(
    [Store] int, 
    [Week] int, 
    [xCount] int 
); 

INSERT INTO #yt 
(
    [Store], 
    [Week], [xCount] 
) 
VALUES 
    (102, 1, 96), 
    (101, 1, 138), 
    (105, 1, 37), 
    (109, 1, 59), 
    (101, 2, 282), 
    (102, 2, 212), 
    (105, 2, 78), 
    (109, 2, 97), 
    (105, 3, 60), 
    (102, 3, 123), 
    (101, 3, 220), 
    (109, 3, 87); 

自分の価値観が知られている場合、あなたはハードコードは、クエリは以下となります。

select * 
from 
(
    select store, week, xCount 
    from yt 
) src 
pivot 
(
    sum(xcount) 
    for week in ([1], [2], [3]) 
) piv; 

SQL Demo

を参照してください。

週番号を動的に生成する必要がある場合、コードは次のようになります。

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

select @cols = STUFF((SELECT ',' + QUOTENAME(Week) 
        from yt 
        group by Week 
        order by Week 
      FOR XML PATH(''), TYPE 
      ).value('.', 'NVARCHAR(MAX)') 
     ,1,1,'') 

set @query = 'SELECT store,' + @cols + ' from 
      (
       select store, week, xCount 
       from yt 
      ) x 
      pivot 
      (
       sum(xCount) 
       for week in (' + @cols + ') 
      ) p ' 

execute(@query); 

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

動的バージョンでは、weekのリストを列に変換する必要があります。どちらも、同じ結果を与える:

| STORE | 1 | 2 | 3 | 
--------------------------- 
| 101 | 138 | 282 | 220 | 
| 102 | 96 | 212 | 123 | 
| 105 | 37 | 78 | 60 | 
| 109 | 59 | 97 | 87 | 
+3

非常に良い!しかし、その列のすべての値がNULLのときに列を削除する方法はありますか? – ZooZ

+0

@ ZooZ [answer below](http://stackoverflow.com/a/27532568/1028230)を参照してください。逐語的に試してみませんでしたが、コンセプトは健全です。 – ruffin

+0

+1 "週が不明な場合は動的SQLを使用する必要があるようですが、当初ハードコード版を使用して正しいコードを見るのが簡単です。異なるQlikview Generic関数(https://community.qlik.com/blogs/qlikviewdesignblog/2014/03/31/generic)とは異なり、異なる "FOR ____ IN(...)"という名前を明示的に指定する必要はありません –

4

これはあなたが何ができるかです:

SELECT * 
FROM yourTable 
PIVOT (MAX(xCount) 
     FOR Week in ([1],[2],[3],[4],[5],[6],[7])) AS pvt 

DEMO

20

これは、数週間のダイナミック#のためです。ここ

全例:私はサブクエリを使用して前に同じことを達成したSQL Dynamic Pivot

DECLARE @DynamicPivotQuery AS NVARCHAR(MAX) 
DECLARE @ColumnName AS NVARCHAR(MAX) 

--Get distinct values of the PIVOT Column 
SELECT @ColumnName= ISNULL(@ColumnName + ',','') + QUOTENAME(Week) 
FROM (SELECT DISTINCT Week FROM #StoreSales) AS Weeks 

--Prepare the PIVOT query using the dynamic 
SET @DynamicPivotQuery = 
    N'SELECT Store, ' + @ColumnName + ' 
    FROM #StoreSales 
    PIVOT(SUM(xCount) 
      FOR Week IN (' + @ColumnName + ')) AS PVTTable' 
--Execute the Dynamic Pivot Query 
EXEC sp_executesql @DynamicPivotQuery 
12

。あなたのオリジナルのテーブルがStoreCountsByWeekと呼ばれ、あなたはストアIDを記載されている別のテーブルを持っていたのであれば、それは次のようになります。

SELECT StoreID, 
    Week1=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=1), 
    Week2=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=2), 
    Week3=(SELECT ISNULL(SUM(xCount),0) FROM StoreCountsByWeek WHERE StoreCountsByWeek.StoreID=Store.StoreID AND Week=3) 
FROM Store 
ORDER BY StoreID 

一つの利点は、この方法には構文がより明確であり、それがなることです他のテーブルに結合して他のフィールドを結果に引き込むことも簡単です。

私の偶然の結果は、数千の行にわたってこのクエリを実行すると1秒未満で完了し、実際には7つのサブクエリがあることです。しかし、コメントに記載されているように、このように計算するのは計算コストが高いので、大量のデータを処理すると予想される場合はこのメソッドを使用することに注意してください。

+6

より簡単ですが、非常に高価な操作ですが、これらのサブクエリはテーブルから返された各行に対して1回実行する必要があります。 – Greg

1
select * from (select name, ID from Empoyee) Visits 
    pivot(sum(ID) for name 
    in ([Emp1], 
    [Emp2], 
    [Emp3] 
    )) as pivottable; 
2

私は基本的に、このSPピボット、任意のテーブルを、この目的のために有用である可能性SPを書いて、新しいテーブルを返すんだが、データのセットだけを旋回したり返し、これはそれを実行する方法です。

Exec dbo.rs_pivot_table @schema=dbo,@table=table_name,@column=column_to_pivot,@agg='sum([column_to_agg]),avg([another_column_to_agg]),', 
     @sel_cols='column_to_select1,column_to_select2,column_to_select1',@new_table=returned_table_pivoted; 

カラム名@aggパラメータで'['でなければなりませんに注意し、パラメータはカンマ','

SP

で終わる必要がありますしてください
Create Procedure [dbo].[rs_pivot_table] 
    @schema sysname=dbo, 
    @table sysname, 
    @column sysname, 
    @agg nvarchar(max), 
    @sel_cols varchar(max), 
    @new_table sysname, 
    @add_to_col_name sysname=null 
As 
--Exec dbo.rs_pivot_table dbo,##TEMPORAL1,tip_liq,'sum([val_liq]),sum([can_liq]),','cod_emp,cod_con,tip_liq',##TEMPORAL1PVT,'hola'; 
Begin 

    Declare @query varchar(max)=''; 
    Declare @aggDet varchar(100); 
    Declare @opp_agg varchar(5); 
    Declare @col_agg varchar(100); 
    Declare @pivot_col sysname; 
    Declare @query_col_pvt varchar(max)=''; 
    Declare @full_query_pivot varchar(max)=''; 
    Declare @ind_tmpTbl int; --Indicador de tabla temporal 1=tabla temporal global 0=Tabla fisica 

    Create Table #pvt_column(
     pivot_col varchar(100) 
    ); 

    Declare @column_agg table(
     opp_agg varchar(5), 
     col_agg varchar(100) 
    ); 

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@table) AND type in (N'U')) 
     Set @ind_tmpTbl=0; 
    ELSE IF OBJECT_ID('tempdb..'+ltrim(rtrim(@table))) IS NOT NULL 
     Set @ind_tmpTbl=1; 

    IF EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(@new_table) AND type in (N'U')) OR 
     OBJECT_ID('tempdb..'+ltrim(rtrim(@new_table))) IS NOT NULL 
    Begin 
     Set @query='DROP TABLE '[email protected]_table+''; 
     Exec (@query); 
    End; 

    Select @query='Select distinct '[email protected]+' From '+(case when @ind_tmpTbl=1 then 'tempdb.' else '' end)[email protected]+'.'[email protected]+' where '[email protected]+' is not null;'; 
    Print @query; 

    Insert into #pvt_column(pivot_col) 
    Exec (@query) 

    While charindex(',',@agg,1)>0 
    Begin 
     Select @aggDet=Substring(@agg,1,charindex(',',@agg,1)-1); 

     Insert Into @column_agg(opp_agg,col_agg) 
     Values(substring(@aggDet,1,charindex('(',@aggDet,1)-1),ltrim(rtrim(replace(substring(@aggDet,charindex('[',@aggDet,1),charindex(']',@aggDet,1)-4),')','')))); 

     Set @agg=Substring(@agg,charindex(',',@agg,1)+1,len(@agg)) 

    End 

    Declare cur_agg cursor read_only forward_only local static for 
    Select 
     opp_agg,col_agg 
    from @column_agg; 

    Open cur_agg; 

    Fetch Next From cur_agg 
    Into @opp_agg,@col_agg; 

    While @@fetch_status=0 
    Begin 

     Declare cur_col cursor read_only forward_only local static for 
     Select 
      pivot_col 
     From #pvt_column; 

     Open cur_col; 

     Fetch Next From cur_col 
     Into @pivot_col; 

     While @@fetch_status=0 
     Begin 

      Select @query_col_pvt='isnull('[email protected]_agg+'(case when '[email protected]+'='+quotename(@pivot_col,char(39))+' then '[email protected]_agg+ 
      ' else null end),0) as ['+lower(Replace(Replace(@opp_agg+'_'+convert(varchar(100),@pivot_col)+'_'+replace(replace(@col_agg,'[',''),']',''),' ',''),'&',''))+ 
       (case when @add_to_col_name is null then space(0) else '_'+isnull(ltrim(rtrim(@add_to_col_name)),'') end)+']' 
      print @query_col_pvt 
      Select @[email protected][email protected]_col_pvt+', ' 

      --print @full_query_pivot 

      Fetch Next From cur_col 
      Into @pivot_col;   

     End  

     Close cur_col; 
     Deallocate cur_col; 

     Fetch Next From cur_agg 
     Into @opp_agg,@col_agg; 
    End 

    Close cur_agg; 
    Deallocate cur_agg; 

    Select @full_query_pivot=substring(@full_query_pivot,1,len(@full_query_pivot)-1); 

    Select @query='Select '[email protected]_cols+','[email protected]_query_pivot+' into '[email protected]_table+' From '+(case when @ind_tmpTbl=1 then 'tempdb.' else '' end)+ 
    @schema+'.'[email protected]+' Group by '[email protected]_cols+';'; 

    print @query; 
    Exec (@query); 

End; 
GO 

これは、実行の例です:

Exec dbo.rs_pivot_table @schema=dbo,@table=##TEMPORAL1,@column=tip_liq,@agg='sum([val_liq]),avg([can_liq]),',@sel_cols='cod_emp,cod_con,tip_liq',@new_table=##TEMPORAL1PVT; 

その後、Select * From ##TEMPORAL1PVTを返します:

enter image description here

関連する問題