Compute the total of SUM(column)

This is valid syntax, too:

       sum(sum(qty)) over ()

It's a bit confusing when one sees it at first but you only have to remember that the window functions - e.g. sum() over () - are applied after the group by so everything that can appear in the select list of a group by query can be placed inside a window aggregate. So (the qty cannot but) the sum(qty) can be placed inside sum() over ():

select sum(qty), itemid, proddte, 
       sum(sum(qty)) over () as grandtotal  
from testtable 
where .... 
group by itemid, proddte ;

Having said that, I'd prefer the GROUPING SETS query provided by Aaron Bertrand. The total sum needs to be shown once and not in every row.

Also note that while the sum of sums can be used to calculate the total sum, if you wanted the total count, you'd have to use the sum of counts (and not the count of counts!):

sum(count(*)) over ()  as grand_count

And if one wanted the average over all the table, it would be even more complicated:

sum(sum(qty)) over ()
/ sum(count(qty)) over ()  as grand_average

because the average of averages is not the same as the average over all. (If you try the avg(avg(qty)) over () you'll see that it may yield a different result than the above grand average.)


CREATE TABLE #foo
(
 itemid int, 
 proddte date,
 qty int
);

INSERT #foo(itemid,proddte,qty) VALUES
(1,'20140101',5),(1,'20140102',7),(2,'20150101',10);


-- if it really needs to be a column with the same value
-- in every row, just calculate once and assign it to a variable

DECLARE @sum int = (SELECT SUM(qty) FROM #foo);

SELECT itemid, proddte, GroupedSum = SUM(qty), GrandTotal = @sum
  FROM #foo
  GROUP BY itemid, proddte;

-- if the grand total can be expressed on its own row, 
-- you can use GROUP BY GROUPING SETS:
SELECT itemid, proddte, SUM(qty)
  FROM #foo GROUP BY GROUPING SETS((),(itemid,proddte));

-- if that syntax is confusing, you can use a less
-- efficient UNION ALL:
SELECT itemid, proddte, SUM(qty)
  FROM #foo GROUP BY itemid,proddte
UNION ALL
SELECT NULL, NULL, SUM(qty) 
  FROM #foo;

GO
DROP TABLE #foo;

The GROUP BY GROUPING SETS is is basically a UNION ALL. The () means just take the SUM regardless of grouping, any other group listed gets aggregated separately. Try GROUP BY GROUPING SETS ((itemid),(itemid,proddte)) to see the difference.

For more details see the documentation:

Using GROUP BY with ROLLUP, CUBE, and GROUPING SETS

As Andriy mentioned, the query above could also be written using:

GROUP BY ROLLUP( (itemid,proddte) )

Note the two columns there are enclosed in an additional pair of parentheses, making them a single unit. Andriy wrote a demo hosted on the Stack Exchange Data Explorer.


One possible way around is to wrap the first GROUP BY into CTE:

WITH
CTE
AS
(
    select
        itemid
        ,proddte
        ,sum(qty) AS SumQty
    from testtable 
    where .... 
    group by itemid, proddte
)
SELECT
    itemid
    ,proddte
    ,SumQty
    ,SUM(SumQty) OVER () AS grandtotal
FROM CTE
;

Tags:

Sql Server

Sum