在SQL Server中使用“透视”将行转换为列

那么我想我真的很密集。 我已经阅读了MS数据透视表的东西,我仍然有问题得到这个正确的。 我看到你们中有些人似乎吃了这些东西,所以我只是决定注册并提出问题。

我有一个正在创build的临时表,我们会说第一列是一个存储号,第二列是一个星期号,最后一列是第三列的总数。 此外,周数是dynamic的,商店数量是静态的。

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 

我希望它能以一个数据透视表的forms出现,如下所示:

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

将数字存储在边上和周边。

谢谢您的帮助。

如果您使用的是SQL Server 2005+,则可以使用PIVOT函数将行中的数据转换为列。

这听起来像你将需要使用dynamicSQL,如果周未知,但更容易看到使用硬编码版本正确的代码最初。

首先,这里有一些快速的表格定义和使用的数据:

 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演示

那么如果你需要dynamic生成星期编号,你的代码将是:

 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演示 。

dynamic版本生成应该转换为列的week数列表。 两者都给出了相同的结果:

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

这是dynamic的#个星期。

完整的例子在这里: 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 

我已经通过使用子查询达到了同样的目的。 因此,如果您的原始表格被称为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 

这种方法的一个优点是语法更清晰,并且可以更容易地join到其他表中,以便将其他字段也纳入到结果中。

我的轶事结果是,在不到一秒的时间内完成了几千行的查询,而且我实际上有7个子查询。 但是正如注释中所指出的那样,这样做在计算上花费更大,因此如果您希望在大量数据上运行,请注意使用此方法。

这是你可以做的:

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

DEMO

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

我正在写一个可以用于这个目的的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 '+@new_table+''; Exec (@query); End; Select @query='Select distinct '+@column+' From '+(case when @ind_tmpTbl=1 then 'tempdb.' else '' end)+@schema+'.'+@table+' where '+@column+' 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('+@opp_agg+'(case when '+@column+'='+quotename(@pivot_col,char(39))+' then '+@col_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 @full_query_pivot=@full_query_pivot+@query_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 '+@sel_cols+','+@full_query_pivot+' into '+@new_table+' From '+(case when @ind_tmpTbl=1 then 'tempdb.' else '' end)+ @schema+'.'+@table+' Group by '+@sel_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将返回:

在这里输入图像描述