Search code examples
sql-servert-sqlpivotsubtotal

Can you subtotal rows and/or columns in a pivot table?


I have a set of queries that outputs a pivot table. Is it possible to obtain row and/or column subtotals for a pivot table ?

My table I am selecting from looks like this

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

etc...

My pivot table query is this

   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;

But I really want it to result in this (which of course it does not total for me)

    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

Thanks for your assistance !

-Don


Solution

  • ;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
    

    Note: If you are using SQL Server 2005 you need to change this:

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

    to

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

    Try on SE Data