计算总和(列)

niq*_*niq 9 sql-server sum

我有这个代码,它总结了某个项目的数量 ( itemid) 及其产品日期代码 ( proddte)。

select sum(qty), itemid, proddte 
from testtable where .... 
group by itemid, proddte
Run Code Online (Sandbox Code Playgroud)

我想要做的是让所有总的qty不管itemid/proddte。我试过了:

select sum(qty), itemid, proddte, sum(qty) over() as grandtotal 
from testtable 
where .... 
group by itemid, proddte
Run Code Online (Sandbox Code Playgroud)

但它说我也应该qtygroup by条款中。如果我这样做,结果将不等于我的预期结果。

它并不绝对需要表示为一个单独的列,每一行都具有相同的值。只要我可以显示总体总数,任何表示都可以接受。

ype*_*eᵀᴹ 10

这也是有效的语法:

       sum(sum(qty)) over ()
Run Code Online (Sandbox Code Playgroud)

当人们第一次看到它时会有点混乱,但您只需要记住窗口函数 - 例如sum() over ()- 在之后应用,group by因此可以出现在按查询组的选择列表中的所有内容都可以放置在窗口聚合中。所以(qty不能但是)sum(qty)可以放在里面sum() over ()

select sum(qty), itemid, proddte, 
       sum(sum(qty)) over () as grandtotal  
from testtable 
where .... 
group by itemid, proddte ;
Run Code Online (Sandbox Code Playgroud)

话虽如此,我更喜欢GROUPING SETSAaron Bertrand 提供的查询。总和需要显示一次,而不是每一行。

另请注意,虽然总和可用于计算总和,但如果您想要总计数,则必须使用计数总和(而不是计数!):

sum(count(*)) over ()  as grand_count
Run Code Online (Sandbox Code Playgroud)

如果想要整个表的平均值,那就更复杂了:

sum(sum(qty)) over ()
/ sum(count(qty)) over ()  as grand_average
Run Code Online (Sandbox Code Playgroud)

因为平均值的平均值与整体的平均值不同。(如果您尝试使用,avg(avg(qty)) over ()您会发现它产生的结果可能与上述总体平均值不同。)


Aar*_*and 9

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;
Run Code Online (Sandbox Code Playgroud)

GROUP BY GROUPING SETSIS基本上是一个UNION ALL。该()装置只取SUM不管分组,列出的任何其他基团被单独聚合。试着GROUP BY GROUPING SETS ((itemid),(itemid,proddte))看看有什么不同。

有关更多详细信息,请参阅文档:

将 GROUP BY 与 ROLLUP、CUBE 和 GROUPING SETS 结合使用

正如 Andriy 提到的,上面的查询也可以使用:

GROUP BY ROLLUP( (itemid,proddte) )
Run Code Online (Sandbox Code Playgroud)

请注意,那里的两列包含在一对额外的括号中,使它们成为一个单元。Andriy编写了一个托管在 Stack Exchange Data Explorer 上的演示

  • @MartinSmith:不,列包含在一对额外的括号中,这使它们成为一个单元。另一方面,“GROUP BY ROLLUP(itemid,proddte)”确实会在“itemid”上产生(额外的)小计(与“GROUP BY ROLLUP((itemid),(proddte))”相同)。[SEDE 演示](http://data.stackexchange.com/dba/query/496936) (4认同)
  • @AndriyM 我已经纠正了。虽然这确实破坏了“不那么令人困惑”的观点,因为它设法混淆了至少一个人:-) (3认同)
  • @AndriyM 我不觉得 `GROUP BY ROLLUP` 不那么令人困惑,但它相当主观。当我阅读诸如 [`不推荐使用的非 ISO 兼容 WITH ROLLUP、WITH CUBE 和 ALL 语法`](https://msdn.microsoft.com/en-us/library/cc645577(v =sql.105).aspx) - 为什么我倾向于使用`GROUPING SETS`。 (2认同)