包含多个列聚合的SQL Server数据透视表

我有一张桌子:

create table mytransactions(country varchar(30), totalcount int, numericmonth int, chardate char(20), totalamount money) 

表中有这些logging:

 insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Australia', 36, 7, 'Jul-12', 699.96) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Australia', 44, 8, 'Aug-12', 1368.71) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Australia', 52, 9, 'Sep-12', 1161.33) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Australia', 50, 10, 'Oct-12', 1099.84) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Australia', 38, 11, 'Nov-12', 1078.94) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Australia', 63, 12, 'Dec-12', 1668.23) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Austria', 11, 7, 'Jul-12', 257.82) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Austria', 5, 8, 'Aug-12', 126.55) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Austria', 7, 9, 'Sep-12', 92.11) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Austria', 12, 10, 'Oct-12', 103.56) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Austria', 21, 11, 'Nov-12', 377.68) Go insert into mytransactions(country, totalcount, numericmonth, chardate, totalamount) values('Austria', 3, 12, 'Dec-12', 14.35) Go 

这是一个select*的样子:

 Country TotalCount numericmonth chardate totalamount --------- ---------- ----------- -------- ----------- Australia 36 7 Jul-12 699.96 Australia 44 8 Aug-12 1368.71 Australia 52 9 Sep-12 1161.33 Australia 50 10 Oct-12 1099.84 Australia 38 11 Nov-12 1078.94 Australia 63 12 Dec-12 1668.23 Austria 11 7 Jul-12 257.82 Austria 5 8 Aug-12 126.55 Austria 7 9 Sep-12 92.11 Austria 12 10 Oct-12 103.56 Austria 21 11 Nov-12 377.68 Austria 3 12 Dec-12 14.35 

我想旋转这个logging集,所以它看起来像这样:

  Australia Australia Austria Austria # of Transactions Total $ amount # of Transactions Total $ amount ----------------- -------------- ----------------- -------------- Jul-12 36 699.96 11 257.82 Aug-12 44 1368.71 5 126.55 Sep-12 52 1161.33 7 92.11 Oct-12 50 1099.84 12 103.56 Nov-12 38 1078.94 21 377.68 Dec-12 63 1668.23 3 14.35 

这是我到目前为止的主要代码:

 select * from mytransactions pivot (sum (totalcount) for country in ([Australia], [Austria])) as pvt 

这是我得到的:

 numericmonth chardate totalamount Australia Austria ----------- -------- ---------- --------- ------- 7 Jul-12 257.82 NULL 11 7 Jul-12 699.96 36 NULL 8 Aug-12 126.55 NULL 5 8 Aug-12 1368.71 44 NULL 9 Sep-12 92.11 NULL 7 9 Sep-12 1161.33 52 NULL 10 Oct-12 103.56 NULL 12 10 Oct-12 1099.84 50 NULL 11 Nov-12 377.68 NULL 21 11 Nov-12 1078.94 38 NULL 12 Dec-12 14.35 NULL 3 12 Dec-12 1668.23 63 NULL 

我可以在表variables循环中手动聚合logging,但似乎可能能够做到这一点。

是可以得到我想要使用数据透视的logging集,或者是否有另一个我不知道的工具?

谢谢

通过应用UNPIVOTPIVOTfunction来获得最终结果,我会做这个稍微不同的事情。 totalcounttotalcounttotalcount列中获取值,并将它们放在一个包含多行的列中。 然后你可以在这些结果上旋转。

 select chardate, Australia_totalcount as [Australia # of Transactions], Australia_totalamount as [Australia Total $ Amount], Austria_totalcount as [Austria # of Transactions], Austria_totalamount as [Austria Total $ Amount] from ( select numericmonth, chardate, country +'_'+col col, value from ( select numericmonth, country, chardate, cast(totalcount as numeric(10, 2)) totalcount, cast(totalamount as numeric(10, 2)) totalamount from mytransactions ) src unpivot ( value for col in (totalcount, totalamount) ) unpiv ) s pivot ( sum(value) for col in (Australia_totalcount, Australia_totalamount, Austria_totalcount, Austria_totalamount) ) piv order by numericmonth 

看演示与SQL小提琴 。

如果您的country名称数量未知,则可以使用dynamicSQL:

 DECLARE @cols AS NVARCHAR(MAX), @colsName AS NVARCHAR(MAX), @query AS NVARCHAR(MAX) select @cols = STUFF((SELECT distinct ',' + QUOTENAME(country +'_'+c.col) from mytransactions cross apply ( select 'TotalCount' col union all select 'TotalAmount' ) c FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'') select @colsName = STUFF((SELECT distinct ', ' + QUOTENAME(country +'_'+c.col) +' as [' + country + case when c.col = 'TotalCount' then ' # of Transactions]' else 'Total $ Amount]' end from mytransactions cross apply ( select 'TotalCount' col union all select 'TotalAmount' ) c FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)') ,1,1,'') set @query = 'SELECT chardate, ' + @colsName + ' from ( select numericmonth, chardate, country +''_''+col col, value from ( select numericmonth, country, chardate, cast(totalcount as numeric(10, 2)) totalcount, cast(totalamount as numeric(10, 2)) totalamount from mytransactions ) src unpivot ( value for col in (totalcount, totalamount) ) unpiv ) s pivot ( sum(value) for col in (' + @cols + ') ) p order by numericmonth' execute(@query) 

看演示与SQL小提琴

两者都给出了结果:

 | CHARDATE | AUSTRALIA # OF TRANSACTIONS | AUSTRALIA TOTAL $ AMOUNT | AUSTRIA # OF TRANSACTIONS | AUSTRIA TOTAL $ AMOUNT | -------------------------------------------------------------------------------------------------------------------------------------- | Jul-12 | 36 | 699.96 | 11 | 257.82 | | Aug-12 | 44 | 1368.71 | 5 | 126.55 | | Sep-12 | 52 | 1161.33 | 7 | 92.11 | | Oct-12 | 50 | 1099.84 | 12 | 103.56 | | Nov-12 | 38 | 1078.94 | 21 | 377.68 | | Dec-12 | 63 | 1668.23 | 3 | 14.35 | 

我已经添加了dynamic查询/解决scheme。

静态的

 SELECT t.chardate, SUM(CASE WHEN t.country='Australia' THEN t.totalcount ELSE 0 END) AS "Australia # of Transactions", SUM(CASE WHEN t.country='Australia' THEN t.totalamount ELSE 0 END) AS "Australia Total $ amount", SUM(CASE WHEN t.country='Austria' THEN t.totalcount ELSE 0 END) AS "Austria # of Transactions", SUM(CASE WHEN t.country='Austria' THEN t.totalamount ELSE 0 END) AS "Austria Total $ amount" FROM mytransactions t GROUP BY t.chardate; 

注意:

1) ORDER BY t.chardate将不起作用,因为chardate列的值是char

2)我的build议是将chardate两列numericmonthnumericyear 。 在最后一种情况下,您可以使用此解决scheme:

 SELECT t.numericyear, t.numericmonth, SUM(CASE WHEN t.country='Australia' THEN t.totalcount ELSE 0 END) AS "Australia # of Transactions", SUM(CASE WHEN t.country='Australia' THEN t.totalamount ELSE 0 END) AS "Australia Total $ amount", SUM(CASE WHEN t.country='Austria' THEN t.totalcount ELSE 0 END) AS "Austria # of Transactions", SUM(CASE WHEN t.country='Austria' THEN t.totalamount ELSE 0 END) AS "Austria Total $ amount" FROM mytransactions t GROUP BY t.numericyear, t.numericmonth ORDER BY BY t.numericyear, t.numericmonth; 

dynamic

 DECLARE @Sql NVARCHAR(MAX)='SELECT t.chardate'; DECLARE @ColumnTemplate NVARCHAR(MAX)='SUM(CASE WHEN t.country=''{country}'' THEN t.totalcount ELSE 0 END) AS "{country} # of Transactions" ,SUM(CASE WHEN t.country=''{country}'' THEN t.totalamount ELSE 0 END) AS "{country} Total $ amount"' SELECT @Sql=@Sql+CHAR(13)+','+REPLACE(@ColumnTemplate, '{country}', REPLACE(c.name,'''','''''')e) FROM ( SELECT DISTINCT t.country AS name FROM mytransactions t ) c SELECT @Sql=@Sql+' FROM mytransactions t GROUP BY t.chardate;' PRINT @Sql; EXEC(@Sql); 

结果:

 SELECT t.chardate ,SUM(CASE WHEN t.country='Australia' THEN t.totalcount ELSE 0 END) AS "Australia # of Transactions" ,SUM(CASE WHEN t.country='Australia' THEN t.totalamount ELSE 0 END) AS "Australia Total $ amount" ,SUM(CASE WHEN t.country='Austria' THEN t.totalcount ELSE 0 END) AS "Austria # of Transactions" ,SUM(CASE WHEN t.country='Austria' THEN t.totalamount ELSE 0 END) AS "Austria Total $ amount" FROM mytransactions t GROUP BY t.chardate; 

注意: SELECT @Sql=@Sql+CHAR(13)+ ... REPLACE(c.name,'''',''''''))REPLACE函数用于防止SQL injections

我用你自己的枢轴作为嵌套查询,来到这个结果:

 SELECT [sub].[chardate], SUM(ISNULL([Australia], 0)) AS [Transactions Australia], SUM(CASE WHEN [Australia] IS NOT NULL THEN [TotalAmount] ELSE 0 END) AS [Amount Australia], SUM(ISNULL([Austria], 0)) AS [Transactions Austria], SUM(CASE WHEN [Austria] IS NOT NULL THEN [TotalAmount] ELSE 0 END) AS [Amount Austria] FROM ( select * from mytransactions pivot (sum (totalcount) for country in ([Australia], [Austria])) as pvt ) AS [sub] GROUP BY [sub].[chardate], [sub].[numericmonth] ORDER BY [sub].[numericmonth] ASC 

这是小提琴 。

最简单,最简单的方法是将主要查询与主要查询一起封装在公用表expression式中,然后进行分组/汇总。

 WITH PivotCTE AS ( select * from mytransactions pivot (sum (totalcount) for country in ([Australia], [Austria])) as pvt ) SELECT numericmonth, chardate, SUM(totalamount) AS totalamount, SUM(ISNULL(Australia, 0)) AS Australia, SUM(ISNULL(Austria, 0)) Austria FROM PivotCTE GROUP BY numericmonth, chardate 

ISNULL将停止NULL值(因为NULL +任何值= NULL