小计和总计SQL Pivot

时间:2013-08-27 15:45:05

标签: sql sql-server pivot

目前有一个脚本可以创建一个数据透视表,其当前年份值减去上一年的值。

use devmreports

-- Creates dynamic values for pivot table
DECLARE @cols AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

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

-- Pivot table for YOY change in booked passengers
set @query
=

'SELECT     Region, 
            CityPair, 
            Year, 
            ' + @cols + '


FROM         
(
    SELECT    ABR.Region, 
                ABR.CityPair, 
                ABR.Year, 
                ABR.Month,
                ABR.Adv_B - ABRP.Adv_B as Total
    FROM    ABR LEFT OUTER JOIN
                      ABRP ON  
                      ABR.Month = ABRP.Month AND 
                      ABR.CityPair = ABRP.CityPair) P
                        PIVOT
                        (
                        SUM(Total) 
                        FOR MONTH IN 
                        (
                        '+@cols+'))as pvt'


execute (@Query)

Current Pivot看起来像这样:

+------------+----------+----+-----+-----+----+
|     Region | CityPair | 8  |  9  | 10  | 11 |
+------------+----------+----+-----+-----+----+
|     A      |        1 | 16 |  17 |  18 |  7 |
|     A      |        2 | 17 | -20 | -10 |  1 |
|     B      |        3 |  5 |   8 |   4 | -3 |
|     B      |        4 | 21 |  10 |   3 |  2 |
|     C      |        5 | 15 | -14 | -12 |  1 |
+------------+----------+----+-----+-----+----+

我想要的是:

+-----------------+----------+----+-----+-----+----+
|       Region    | CityPair | 8  |  9  | 10  | 11 |
+-----------------+----------+----+-----+-----+----+
|     A           |        1 | 16 |  17 |  18 |  7 |
|     A           |        2 | 17 | -20 | -10 |  1 |
|     A Total     |          | 33 |  -3 |   8 |  8 |
|     B           |        3 |  5 |   8 |   4 | -3 |
|     B           |        4 | 21 |  10 |   3 |  2 |
|     B Total     |          | 26 |  18 |   7 | -1 |
|     C           |        5 | 15 | -14 | -12 |  1 |
|     C Total     |          | 15 | -14 | -12 |  1 |
|     Grand Total |          | 74 |   1 |   3 |  8 |
+-----------------+----------+----+-----+-----+----+

非常感谢任何协助。

2 个答案:

答案 0 :(得分:3)

我的建议是使用GROUP BY ROLLUP来获取总行数。

如果您对查询进行硬编码,则基本语法为:

select 
  case 
    when region is null then 'Grand Total' 
    when citypair is null then region +' Total' 
    else region end region,
  coalesce(cast(citypair as varchar(10)), '') citypair,
  sum([8]) [8], 
  sum([9]) [9]
from
(
  select region, citypair, month, total
  from yourtable
) d
pivot
(
  sum(total)
  for month in ([8], [9])
) piv
GROUP BY rollup(region, citypair);

SQL Fiddle with Demo。然后,要使用动态SQL版本,您可以更改要使用的代码:

-- Creates dynamic values for pivot table
DECLARE @cols AS NVARCHAR(MAX),
    @colsRollup AS NVARCHAR(MAX),
    @query  AS NVARCHAR(MAX)

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

select @colsRollup = STUFF((SELECT ', sum(' + QUOTENAME(month)+ ') as '+ QUOTENAME(month)
                    from ABR
                    group by ',' + QUOTENAME(month)
                    order by datalength(',' + QUOTENAME(month))
            FOR XML PATH(''), TYPE
            ).value('.', 'NVARCHAR(MAX)') 
        ,1,1,'')

-- Pivot table for YOY change in booked passengers
set @query
=

'SELECT     
      case 
        when region is null then ''Grand Total'' 
        when citypair is null then region +'' Total' '
        else region end region,
      coalesce(cast(citypair as varchar(10)), '''') citypair, 
            ' + @colsRollup + '


FROM         
(
    SELECT    ABR.Region, 
                ABR.CityPair, 
                ABR.Year, 
                ABR.Month,
                ABR.Adv_B - ABRP.Adv_B as Total
    FROM    ABR LEFT OUTER JOIN
                      ABRP ON  
                      ABR.Month = ABRP.Month AND 
                      ABR.CityPair = ABRP.CityPair
) P
PIVOT
(
  SUM(Total) 
  FOR MONTH IN ('+@cols+')
)as pvt
GROUP BY rollup(region, citypair);'


execute sp_executesql @Query

答案 1 :(得分:0)

这就是为什么我更喜欢用聚合而不是pivot手动转动。这是一个查询,它将显示总计和总计的所有总和:

select
    case
        when grouping(Region) = 1 then 'Grand Total'
        when grouping(CityPair) = 1 then Region + ' Total'
        else Region
    end as Region,
    isnull(cast(CityPair as nvarchar(max)), '') as CityPair,
    sum(case when Month = 8 then Value end) as [8],
    sum(case when Month = 9 then Value end) as [9],
    sum(case when Month = 10 then Value end) as [10],
    sum(case when Month = 11 then Value end) as [11]
from test
group by rollup(Region, CityPair)

sql fiddle demo

这是动态的:

declare @stmt nvarchar(max)

select
    @stmt = isnull(@stmt + ',', '') + 
    'sum(case when Month = ' + cast(Month as nvarchar(max)) +
    ' then Value end) as [' + cast(Month as nvarchar(max)) + ']'
from (select distinct Month from test) as a

select @stmt = '
select
    case
        when grouping(Region) = 1 then ''Grand Total''
        when grouping(CityPair) = 1 then Region + '' Total''
        else Region
    end as Region,
    isnull(cast(CityPair as nvarchar(max)), ''''), ' + @stmt + '
from test
group by rollup(Region, CityPair)'

exec sp_executesql @stmt = @stmt

sql fiddle demo

一如既往,尽量让它尽可能可读。

我建议使用group by rollup代替with rollup,因为最后一个将被弃用:

  

WITH ROLLUP此功能将在以后的版本中删除   Microsoft SQL Server。避免在新开发中使用此功能   工作,并计划修改当前使用此功能的应用程序。