【问题标题】:Can you subtotal rows and/or columns in a pivot table?您可以对数据透视表中的行和/或列进行小计吗?
【发布时间】:2011-12-17 01:35:23
【问题描述】:

我有一组输出数据透视表的查询。是否可以获取数据透视表的行和/或列小计?

我从中选择的表看起来像这样

    Site     FormID   Present
    Site 1   Form A      Yes
    Site 1   Form B      Yes
    Site 1   Form D      Yes

等等……

我的数据透视表查询是这样的

   SELECT *
   FROM (SELECT Site, COUNT(FormID) AS NumberOfForms,FormID
         FROM @CRFCount WHERE Present='Yes'
         GROUP BY Site, FormID) d
   PIVOT
   (SUM(NumberOfForms)
   FOR [Site] IN ([Site 1], [Site 2], [Site 3])
   )  AS p;

但我真的希望它能够导致这个(当然这对我来说并不完全)

    FormID  Site 1  Site 2  Site 3  Total
    Form A      8      8      15    31
    Form B     14      4    NULL    18
    Form C     14   NULL    NULL    14
    Form D     15      3      16    34
    Form E     12      4    NULL    16
    Form F     14      5       5    24
    Form G     14      8       6    28
    Form H     22     10      15    47
    Form I     15     10      16    41
    Form J     15      5      16    36
    Total     143     57      89   289

感谢您的帮助!

-唐

【问题讨论】:

    标签: sql-server tsql pivot subtotal


    【解决方案1】:
    ;WITH C as
    (
      SELECT FormID,
             [Site 1],
             [Site 2],
             [Site 3],
             (SELECT SUM(S)
              FROM (VALUES([Site 1]),
                          ([Site 2]),
                          ([Site 3])) AS T(S)) as Total
       FROM (SELECT Site, COUNT(FormID) AS NumberOfForms,FormID
             FROM @CRFCount WHERE Present='Yes'
             GROUP BY Site, FormID) d
       PIVOT
       (SUM(NumberOfForms)
       FOR [Site] IN ([Site 1], [Site 2], [Site 3])
       )  AS p
    )
    SELECT *
    FROM
      (
        SELECT FormID,
               [Site 1],
               [Site 2],
               [Site 3],
               Total
        FROM C
        UNION ALL
        SELECT 'Total',
               SUM([Site 1]),
               SUM([Site 2]),
               SUM([Site 3]),
               SUM(Total)
        FROM C
      ) AS T
    ORDER BY CASE WHEN FormID = 'Total' THEN 1 END
    

    注意:如果您使用的是 SQL Server 2005,则需要更改:

     (SELECT SUM(S)
      FROM (VALUES([Site 1]),
                  ([Site 2]),
                  ([Site 3])) AS T(S)) as Total
    

     (SELECT SUM(S)
      FROM (SELECT [Site 1] UNION ALL
            SELECT [Site 2] UNION ALL
            SELECT [Site 3]) AS T(S)) as Total
    

    试试SE Data

    【讨论】:

      【解决方案2】:

      试试这个(未测试):

      SELECT *
      FROM
      (
          SELECT
              Site = case when grouping(Site)=1 then 'All' else Site end,
              FormID = case when grouping(FormID)=1 then 'All' else cast(FormID as varchar(100)) end,
              measure = count(NumberOfForms)
          FROM @CRFCount 
             -- chose below
             GROUP BY Site, FormID with cube --(ms sql 2005)
             --group by grouping sets(Site, FormID, (Site, FormID), ()) --(ms sql 2008)
      ) AS BOM
      PIVOT  (max(measure) FOR [Site] IN ([Site 1], [Site 2], [Site 3], [All]))
      as pv
      

      【讨论】:

      • 在 SQL Server 2008 中,它可能只是 GROUP BY CUBE (Site, FormID),尽管您的 GROUPING SETS () 等效于 CUBE () 也是正确的。
      【解决方案3】:

      示例表

      SELECT * INTO #TEMP 
      FROM
      (
          SELECT 'Site 1' [Site],   'Form A' [FormID],      'Yes' Present
          UNION ALL
          SELECT 'Site 1',   'Form B',      'Yes'
          UNION ALL
          SELECT 'Site 1',   'Form C',      'Yes'
          UNION ALL
          SELECT 'Site 1',   'Form B',      'NO'
          UNION ALL
          SELECT 'Site 1',   'Form C',      'NO'
          UNION ALL
          SELECT 'Site 2',   'Form A',      'Yes'
          UNION ALL
          SELECT 'Site 2',   'Form A',      'Yes'
          UNION ALL
          SELECT 'Site 2',   'Form B',      'Yes'
          UNION ALL
          SELECT 'Site 2',   'Form B',      'NO'
          UNION ALL
          SELECT 'Site 2',   'Form C',      'Yes'
          UNION ALL
          SELECT 'Site 3',   'Form B',      'Yes'
          UNION ALL
          SELECT 'Site 3',   'Form A',      'Yes'
          UNION ALL
          SELECT 'Site 3',   'Form C',      'Yes'
          UNION ALL
          SELECT 'Site 3',   'Form A',      'Yes'
      )TAB
      

      1.行和列总计

      -- Get the columns for dynamic pivot
      DECLARE @cols NVARCHAR (MAX)
      
      SELECT @cols = COALESCE (@cols + ',[' + [Site] + ']', '[' + [Site] + ']')
                     FROM (SELECT DISTINCT [Site] FROM  #TEMP WHERE Present='YES') PV 
                     ORDER BY [Site] 
      -- Since we need Total in last column, we append it at last
      SELECT @cols += ',[Total]'
      

      您可以使用CUBE 获取旋转时的行和列总数。更多关于CUBEhere

      DECLARE @query NVARCHAR(MAX)
      SET @query = 'SELECT FORMID,' + @cols + ' FROM 
                   (
                       SELECT 
                       ISNULL([SITE],''Total'')[SITE], 
                       SUM(CNT)CNT , 
                       ISNULL(FORMID,''Total'')FORMID              
                       FROM 
                       (
                          SELECT DISTINCT [SITE],FORMID,
                          COUNT(FORMID) OVER(PARTITION BY [SITE],FORMID) CNT
                          FROM #TEMP
                          WHERE PRESENT=''YES''
                       )TAB
                       GROUP BY [SITE],FORMID
                       WITH CUBE
                   ) x
                   PIVOT 
                   (
                       MIN(CNT)
                       FOR [SITE] IN (' + @cols + ')
                  ) p
                  ORDER BY CASE WHEN (FORMID=''Total'') THEN 1 ELSE 0 END,FORMID' 
      
      EXEC SP_EXECUTESQL @query
      

      2。仅行总计

      您可以使用ROLLUP 获取行总数。

      -- Get the columns for dynamic pivot
      DECLARE @cols NVARCHAR (MAX)
      
      SELECT @cols = COALESCE (@cols + ',[' + [Site] + ']', '[' + [Site] + ']')
                     FROM (SELECT DISTINCT [Site] FROM  #TEMP WHERE Present='YES') PV 
                     ORDER BY [Site] 
      
      
      
      DECLARE @query NVARCHAR(MAX)
      SET @query = 'SELECT FORMID,' + @cols + ' FROM 
                   (
                       SELECT 
                       ISNULL([SITE],''Total'')[SITE], 
                       SUM(CNT)CNT , 
                       ISNULL(FORMID,''Total'')FORMID              
                       FROM 
                       (
                          SELECT DISTINCT [SITE],FORMID,
                          COUNT(FORMID) OVER(PARTITION BY [SITE],FORMID) CNT
                          FROM #TEMP
                          WHERE PRESENT=''YES''
                       )TAB
                       GROUP BY [SITE],FORMID
                       WITH ROLLUP
                   ) x
                   PIVOT 
                   (
                       MIN(CNT)
                       FOR [SITE] IN (' + @cols + ')
                  ) p
                  ORDER BY CASE WHEN (FORMID=''Total'') THEN 1 ELSE 0 END,FORMID' 
      
      EXEC SP_EXECUTESQL @query
      

      3.仅列总计

      GROUP BY [SITE],FORMID 更改为GROUP BY FORMID,[SITE]

      -- Get the columns for dynamic pivot
      DECLARE @cols NVARCHAR (MAX)
      
      SELECT @cols = COALESCE (@cols + ',[' + [Site] + ']', '[' + [Site] + ']')
                     FROM (SELECT DISTINCT [Site] FROM  #TEMP WHERE Present='YES') PV 
                     ORDER BY [Site] 
      
       --Since we need Total in last column, we append it at last
      SELECT @cols += ',[Total]'
      
      
      DECLARE @query NVARCHAR(MAX)
      SET @query = 'SELECT FORMID,' + @cols + ' FROM 
                   (
                       SELECT 
                       ISNULL([SITE],''Total'')[SITE], 
                       SUM(CNT)CNT , 
                       ISNULL(FORMID,''Total'')FORMID              
                       FROM 
                       (
                          SELECT DISTINCT [SITE],FORMID,
                          COUNT(FORMID) OVER(PARTITION BY [SITE],FORMID) CNT
                          FROM #TEMP
                          WHERE PRESENT=''YES''
                       )TAB
                       GROUP BY FORMID,[SITE]
                       WITH ROLLUP
                   ) x
                   PIVOT 
                   (
                       MIN(CNT)
                       FOR [SITE] IN (' + @cols + ')
                  ) p
                  WHERE FORMID <> ''Total''
                  ORDER BY FORMID' 
      
      EXEC SP_EXECUTESQL @query
      

      现在,如果你想用零替换 null,你可以在动态透视之前使用下面的代码。

      DECLARE @NulltoZeroCols NVARCHAR (MAX)
      
      SELECT @NullToZeroCols = SUBSTRING((SELECT ',ISNULL(['+[Site]+'],0) AS ['+[Site]+']' 
      FROM (SELECT DISTINCT [Site] FROM #TEMP)TAB  
      ORDER BY [Site] FOR XML PATH('')),2,8000) 
      
      SELECT @NullToZeroCols += ',ISNULL([Total],0) AS [Total]'
      

      并且在动态枢轴的最外层查询中,将@cols 变量替换为@NullToZeroCols

      【讨论】:

        猜你喜欢
        • 2017-07-04
        • 1970-01-01
        • 2013-03-12
        • 1970-01-01
        • 1970-01-01
        • 2021-05-28
        • 2011-12-05
        • 2020-06-03
        • 2017-08-09
        相关资源
        最近更新 更多