按查询分组并求和所有值
group by query with sum all value
我在 SQL 中有产品 table 像这样:
productID Type Amount
1046 1 4
1046 1 5
1046 2 10
1047 1 5
1047 2 3
如何进行查询,输出如下:
productID Type TotalTypeAmount TotalPerProductID
1046 1 9 19
1046 2 10 19
1047 1 5 8
1047 2 3 8
如果您使用的是 SQL 服务器或 Postgres,则以下内容应该有效:
WITH CTE
AS
(
SELECT
productID,
SUM(Amount) AS TotalAllType
FROM Product
GROUP BY productID
)
SELECT
productID,
Type,
SUM(Amount) AS TotalTypeAmount
,TotalAllType
FROM Product AS P
LEFT JOIN CTE ON CTE.productID=P.productID
GROUP BY productID,Type, TotalAllType;
这样我们也可以做到
Select
T.productID,
T.Type,
T.Tamount,
TT.FAmount
from (
select
productID,
Type,
SUM(Amount)Tamount
from
Product
GROUP BY productID, Type
)T
INNER JOIN (
select
productID,
SUM(Amount)FAmount
from
Product
GROUP BY productID
)TT
ON T.productID = TT.productID
一种更 compact/professional 的方式,应该也更快,因为它不需要连接:
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)
是 "the sum of sum_per_productid_and_type grouped by productid only"
假设我们有更简单的查询:
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
。我们可以引入一个window函数,只按productid对所有数据进行求和,它会产生重复求和的结果,而不是导致行数减少,即:
id1, type1, 100, 300
id1, type2, 200, 300
id2, type1, 300, 700
id2, type2, 400, 700
这是因为 window 函数执行 grouping/summing 然后将结果应用于每一行。
重要的是要理解 window 操作是在分组和求和完成之后执行的,但在我们为列提供 SELECT 中的任何别名之前。如果在 window 函数是 运行 之前分配了列名,那么我们可以说 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)
是"the sum that is done by the GROUP BY",
- 大写的外层
SUM(…) OVER(…)
是"the sum that is done by the window function"
我们不得不重复自己并说 SUM(SUM(amount))
因为当时 window 函数是 运行,group by 完成的总和(即我们想要的东西total up) 没有自己的名字 - 它只是被称为 SUM(amount)
我在 SQL 中有产品 table 像这样:
productID Type Amount
1046 1 4
1046 1 5
1046 2 10
1047 1 5
1047 2 3
如何进行查询,输出如下:
productID Type TotalTypeAmount TotalPerProductID
1046 1 9 19
1046 2 10 19
1047 1 5 8
1047 2 3 8
如果您使用的是 SQL 服务器或 Postgres,则以下内容应该有效:
WITH CTE
AS
(
SELECT
productID,
SUM(Amount) AS TotalAllType
FROM Product
GROUP BY productID
)
SELECT
productID,
Type,
SUM(Amount) AS TotalTypeAmount
,TotalAllType
FROM Product AS P
LEFT JOIN CTE ON CTE.productID=P.productID
GROUP BY productID,Type, TotalAllType;
这样我们也可以做到
Select
T.productID,
T.Type,
T.Tamount,
TT.FAmount
from (
select
productID,
Type,
SUM(Amount)Tamount
from
Product
GROUP BY productID, Type
)T
INNER JOIN (
select
productID,
SUM(Amount)FAmount
from
Product
GROUP BY productID
)TT
ON T.productID = TT.productID
一种更 compact/professional 的方式,应该也更快,因为它不需要连接:
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)
是 "the sum of sum_per_productid_and_type grouped by productid only"
假设我们有更简单的查询:
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
。我们可以引入一个window函数,只按productid对所有数据进行求和,它会产生重复求和的结果,而不是导致行数减少,即:
id1, type1, 100, 300
id1, type2, 200, 300
id2, type1, 300, 700
id2, type2, 400, 700
这是因为 window 函数执行 grouping/summing 然后将结果应用于每一行。
重要的是要理解 window 操作是在分组和求和完成之后执行的,但在我们为列提供 SELECT 中的任何别名之前。如果在 window 函数是 运行 之前分配了列名,那么我们可以说 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)
是"the sum that is done by the GROUP BY", - 大写的外层
SUM(…) OVER(…)
是"the sum that is done by the window function"
我们不得不重复自己并说 SUM(SUM(amount))
因为当时 window 函数是 运行,group by 完成的总和(即我们想要的东西total up) 没有自己的名字 - 它只是被称为 SUM(amount)