在T-SQL中创建复杂的数据透视表

时间:2014-10-06 20:31:53

标签: sql tsql sql-server-2008-r2

我正在使用SQL Server 2008 R2和T-SQL。这些是缩写的例子。

我的表/视图包含以下字段

Table/View
    ReportID,   
    UnitName,
    UnitID,
    CaseDefinitionID,
    CaseDefinition,
    DateOfDelivery,
    YEAR(DateOfDelivery) AS [Year],
    MONTH(DateOfDelivery) AS [Month],
    DATENAME(m,DateOfDelivery) AS [Month name]

我的目标报告是:

Unit    |   Case type 1|    Case type 2|    Case total|
Unit A  |            36|             40|            76|

    2013|            20|             18|            38|
     Jan|            10|
     Feb|            10|

    2014|            16|
     Mar|             8|
     Dec|             8|

Unit B  |            12|
    2013|            12|
     Jan|             6|
     May|             6|

Grand total|         48|

月份行可以为空,NULL内容也可以。示例报告不完整以帮助澄清。

到目前为止的进展是以下查询:

SELECT *
FROM
(
    SELECT
        PCT.[Year],
        PCT.UnitName AS [Unit],
        PCT.UnitID,
        PCT.CaseDefinition AS [Case definition]

    FROM
        PivotBase AS PCT            
) AS P1

PIVOT
(
    COUNT(UnitID)
    FOR [Case definition] IN ([Case type 1],[Case type 2])
) AS P2 

这将产生下表

Year|Unit   |Case type 1|Case type 2|
2013|Unit A |       20  |         18|
2014|Unit A |       16  |         22|
2013|Unit B |       6   |          8|
2014|Unit B |       6   |          8|

不需要动态SQL

到目前为止,我的阅读内容涵盖了许多选项,但我仍然不知道下一步该怎么做。如何生成所需的报告。

2 个答案:

答案 0 :(得分:2)

可以使用一些花哨的汇总(SQL Fiddle

;WITH
    CTE1 AS
    (
        SELECT      UnitName,
                    [Year],
                    [Month],
                    CaseDefinition,
                    GROUPING_ID(UnitName,[Year],[Month],CaseDefinition) 
                                        AS GroupingID,
                    CASE GROUPING_ID(CaseDefinition,UnitName,[Year],[Month])
                        WHEN 0 THEN UnitName + '-' + CAST(Year AS varchar(4)) + '-' + RIGHT('0' + CAST([Month] AS varchar(10)),2)
                        WHEN 1 THEN UnitName + '-' + CAST(Year AS varchar(4))
                        WHEN 3 THEN UnitName
                        WHEN 7 THEN 'zzz'  -- So that grand total appears at the bottom
                        ELSE NULL
                    END                 AS GroupingLevel,
                    CASE GROUPING_ID(CaseDefinition,UnitName,[Year],[Month])
                        WHEN 0 THEN '    ' + CASE [Month]
                                                WHEN 1 THEN 'Jan'
                                                WHEN 2 THEN 'Feb'
                                                WHEN 3 THEN 'Mar'
                                                WHEN 4 THEN 'Apr'
                                                WHEN 5 THEN 'May'
                                                WHEN 6 THEN 'Jun'
                                                WHEN 7 THEN 'Jul'
                                                WHEN 8 THEN 'Aug'
                                                WHEN 9 THEN 'Sep'
                                                WHEN 10 THEN 'Oct'
                                                WHEN 11 THEN 'Nov'
                                                WHEN 12 THEN 'Dec'
                                             END
                        WHEN 1 THEN '  '   + CAST([Year] AS varchar(4))
                        WHEN 3 THEN UnitName
                        WHEN 7 THEN 'Grand Total'
                    END                 AS DisplayName,
                    COUNT(UnitID)       AS UnitCount
        FROM        PivotBase
        GROUP BY    GROUPING SETS(
                        (CaseDefinition),
                        (UnitName,CaseDefinition),
                        (UnitName,[Year],[CaseDefinition]),
                        (UnitName,[Year],[Month],CaseDefinition)
                    )
    )

SELECT      pvt.GroupingLevel,
            pvt.DisplayName,
            pvt.[Case Type 1],
            pvt.[Case Type 2],
            ISNULL(pvt.[Case Type 1],0) + ISNULL(pvt.[Case Type 2],0) AS [Case Total]
FROM        CTE1
PIVOT       (
                SUM(UnitCount) FOR CaseDefinition IN ([Case Type 1],[Case Type 2])
            ) pvt
ORDER BY    GroupingLevel

<强>解释

  1. GROUPING SET( (set1), (set2), (set3) )定义了汇总级别。对于 UnitID内的每个唯一组合,然后set1,然后set2

  2. ,您将获得set3的计数
  3. GROUPING_ID是这里最晦涩的功能。把它想象成一个小面具。如果聚合了列,则其位值设置为1.例如:GROUPING_ID(field3, field2, field1, field0)。如果未聚合所有4,则位掩码为0000 = 0。如果汇总了field0,则返回的值为0001 = 1,依此类推。

  4. 您可以将最后一个SELECT替换为SELECT * FROM CTE1,以查看查询的内部工作情况。

答案 1 :(得分:2)

您可以通过在月份和年份上旋转,然后使用WITH ROLLUP

来到达那里
WITH data 
     AS (SELECT * 
         FROM   (SELECT Dateadd(month, Datediff(month, 0, PCT.dateofdelivery), 0 
                        ) 
                        MonthYear, 
                        PCT.unitid, 
                        PCT.unitname 
                        AS 
                        [Unit], 
                        PCT.casedefinition 
                        AS 
                                [Case definition] 
                 FROM   pivotbase AS PCT) AS P1 
                PIVOT ( Count(unitid) 
                      FOR [case definition] IN ([Case type 1], 
                                                [Case type 2]) ) AS p2), 
     rollup 
     AS (SELECT Month(monthyear)           Month, 
                unit                       unitX, 
                Year(monthyear)            Year, 
                Sum([case type 1])         [case type 1], 
                Sum([case type 2])         [case type 2], 
                Grouping(unit)             GUnit, 
                Grouping(Month(monthyear)) gm, 
                Grouping(Year(monthyear))  gy 
         FROM   data 
         GROUP  BY unit, 
                   Year(monthyear), 
                   Month(monthyear) WITH rollup) 
SELECT COALESCE(Cast(month AS VARCHAR), Cast(year AS VARCHAR), unitx, 
       'Grand Total') 
       Unit, 
       [case type 1], 
       [case type 2] 
FROM   rollup 
ORDER  BY gunit, 
          unitx, 
          year, 
          gm DESC, 
          month 

SQLFiddle