(SQL 初学者问题)帮助理解 HAVING 和 GROUP BY 是如何应用的
Posted
技术标签:
【中文标题】(SQL 初学者问题)帮助理解 HAVING 和 GROUP BY 是如何应用的【英文标题】:(SQL Beginner Question) help understanding how HAVING and GROUP BY are applied 【发布时间】:2021-05-21 11:47:55 【问题描述】:我正在处理 SQL Server 中的 Northwinds 练习数据库的练习问题,但我无法理解此解决方案的工作原理。任何解释它的帮助将不胜感激(欢迎对我的代码效率或可读性提出任何批评 - 我是初学者)。
练习题有两个问题。
第一个是:定义在 2016 年至少下过 1 笔价值等于或大于 10,000 美元的订单的客户。
为此我写道:
SELECT
o.CustomerID,
c.CompanyName,
o.OrderID,
SUM(d.UnitPrice*d.Quantity) AS 'TotalOrderAmount'
FROM
Orders AS o
JOIN
Customers AS c ON o.CustomerID = c.CustomerID
JOIN
OrderDetails AS d ON d.OrderID = o.OrderID
WHERE
YEAR(o.OrderDate) = 2016
GROUP BY
o.CustomerID, c.CompanyName, o.OrderID
HAVING
SUM(d.UnitPrice * d.Quantity) >= 10000
ORDER BY
TotalOrderAmount DESC
第二个问题是:定义 2016 年订单总额为 15,000 美元或以上的客户。
在书后的帮助下我写的解决方案是:
SELECT
c.CustomerID,
c.CompanyName,
SUM(d.UnitPrice*d.Quantity) AS 'TotalOrderAmount'
FROM
Orders AS o
JOIN
Customers AS c ON o.CustomerID = c.CustomerID
JOIN
OrderDetails AS d ON d.OrderID = o.OrderID
WHERE
YEAR(o.OrderDate) = 2016
GROUP BY
c.CustomerID, c.CompanyName
HAVING
SUM(d.UnitPrice * d.Quantity) >= 15000
ORDER BY
TotalOrderAmount DESC
我只是不明白如何将单个订单的 SUM 报表转换为询问客户的年度总额是多少。这本书特别提到了更改 GROUP BY 级别,所以我只是这样做了,但我仍然不确定它是如何解决的。
提前致谢。
【问题讨论】:
我真的不明白你在这里不明白什么。具体来说,您在这里不清楚的是什么? 仔细查看 GROUP BY 子句。有什么区别?一个有 OrderID,一个没有。那么这对 SUM 计算的值有什么不同呢? 第一个查询不完全正确,如果有多个这样的订单,它会给相同的客户多次。顺便说一句:YEAR(...) =
效率低下,通常使用date >= 'yyyy-01-01' AND date < 'nxtyear-01-01'
会更快
@Larnu 第二个问题想要的年度合并订单总额大于或等于 15,000 美元,但在 HAVING 中,我认为它只是在寻找超过 15,000 美元的订单,而不是年终总销售额 15,000 美元的订单。
@Larnu 也许我误解了这个问题。当答案部分说“这里只需要注释掉 Select 子句和 Group By 子句中对 OrderID 的引用时,我有点被甩了。这样做,我们在客户级别进行分组,而不是在订单级别。”
【参考方案1】:
试试这个:删除HAVING
子句,并将结果过滤到单个客户和公司,这样您就可以更仔细地查看它们:
SELECT
o.CustomerID,
c.CompanyName,
o.OrderID,
SUM(d.UnitPrice*d.Quantity) AS TotalOrderAmount
FROM
Orders AS o
JOIN
Customers AS c ON o.CustomerID = c.CustomerID
JOIN
OrderDetails AS d ON d.OrderID = o.OrderID
WHERE
YEAR(o.OrderDate) = 2016
-- pick a customer and company that gives you some orders
AND c.CustomerID = 12345
AND c.CompanyName = 'Acme Corp'
GROUP BY
o.CustomerID, c.CompanyName, o.OrderID
您应该会为每个 OrderID
看到不同的 TotalOrderAmount
。
现在从SELECT
子句和GROUP BY
子句中删除o.OrderID
:
SELECT
o.CustomerID,
c.CompanyName,
SUM(d.UnitPrice*d.Quantity) AS TotalOrderAmount
FROM
Orders AS o
JOIN
Customers AS c ON o.CustomerID = c.CustomerID
JOIN
OrderDetails AS d ON d.OrderID = o.OrderID
WHERE
YEAR(o.OrderDate) = 2016
-- use the same filters as before
AND c.CustomerID = 12345
AND c.CompanyName = 'Acme Corp'
GROUP BY
o.CustomerID, c.CompanyName
您现在应该只看到一行,它的 TotalOrderAmount
将是所有之前的 TotalOrderAmount
值加在一起。这是因为以前因为具有不同 OrderID
值而分开的行现在被合并到同一个组中。当我们计算那个新的更大组的SUM
时,它包含了之前那些组的所有值。
HAVING
子句只查看与TotalOrderAmount
列相同的等式,并使用它从结果中过滤整个组。
【讨论】:
以上是关于(SQL 初学者问题)帮助理解 HAVING 和 GROUP BY 是如何应用的的主要内容,如果未能解决你的问题,请参考以下文章