一种更紧凑/更专业的方式,也应该更快,因为它不需要加入:
SELECT
productID,
Type,
SUM(Amount) AS TotalTypeAmount,
SUM(SUM(Amount)) OVER (PARTITION BY productID) as TotalPerProduct
FROM
Product
GROUP BY
productID,Type
http://sqlfiddle.com/#!6/ca308/4
SUM(amount) 是每个 productid,type 的金额总和,即如果您刚刚执行 GROUP BY,您将获得的总和,因此每个 productid 将有多个不同的总和,因为它们被分解为 type亚组。 SUM(SUM(amount)) PARTITION BY(productid) 是“sum_per_productid_and_type 仅按 productid 分组的总和”
假设我们有更简单的查询:
SELECT
productID,
Type,
SUM(Amount) AS TotalTypeAmount
FROM
Product
GROUP BY
productID,Type
这可能会产生如下结果:
id1, type1, 100
id1, type2, 200
id2, type1, 300
id2, type2, 400
我们可以看到所有id1 的总数为300,所有id2 的总数为700。我们可以引入一个窗口函数来仅按 productid 对所有数据求和,它会在求和重复的地方产生结果,而不是导致行数减少,即:
id1, type1, 100, 300
id1, type2, 200, 300
id2, type1, 300, 700
id2, type2, 400, 700
这是因为窗口函数会进行分组/求和,然后将结果应用于每一行。
重要的是要了解窗口操作是在分组和求和完成之后执行的,但在我们在 SELECT 中为列指定任何别名之前。如果在窗口函数运行之前已经分配了列名,那么我们可以说SUM(TotalTypeAmount) 而不是SUM(SUM(Amount)):
SELECT
productID,
Type,
SUM(Amount) AS TotalTypeAmount,
SUM(TotalTypeAmount) OVER (PARTITION BY productID) as TotalPerProduct
FROM
Product
GROUP BY
productID,Type
但这是一个语法错误,因为我们不能在定义它的同一个 SELECT 中引用 TotalTypeAmount。我们可以通过使用子查询来实现这一点:
SELECT
x.productID,
x.Type,
x.TotalTypeAmount, --here we use it after it has been defined in the subquery
SUM(x.TotalTypeAmount) OVER (PARTITION BY x.productID) as TotalPerProduct
FROM
(
SELECT
productID,
Type,
SUM(Amount) AS TotalTypeAmount --here we define it
FROM
Product
GROUP BY
productID,Type
) x
但它比它需要的更复杂。
本质上,虽然看起来很奇怪,但我们只需要在看到时记住:
SUM(sum(…)) OVER(PARTITION BY …)
…
group by …
- 小写的内部
sum(amount) 是“GROUP BY 完成的总和”,并且
- 大写的外部
SUM(…) OVER(…)是“窗口函数完成的总和”
我们不得不重复自己并说SUM(SUM(amount)),因为在运行窗口函数时,group by 完成的总和(即我们想要总计的东西)没有自己的名字 - 它刚刚被称为SUM(amount)