问题描述
不允许在没有“GROUP BY”的情况下使用“HAVING”:
SELECT *
FROM products
HAVING unitprice > avg(unitprice)
列“products.UnitPrice”在 HAVING 子句中无效,因为它既没有包含在聚合函数中,也没有包含在 GROUP BY 子句中。
但是在“EXISTS”下放置相同的代码时 - 没问题:
SELECT *
FROM products p
WHERE EXISTS (SELECT 1
FROM products
HAVING p.unitprice > avg(unitprice))
你能解释一下原因吗?
解决方法
第一个查询中的错误很明显 UnitPrice 不是聚合的一部分,也不是分组依据 而在您的第二个查询中,您正在比较表 "products p" 中的 p.unitprice,该表不需要是聚合或 group by 的一部分,您的第二个查询等效于:
select * from products p
where p.unitprice > (select avg(unitprice) FROM products)
这也许更清楚,那个 sql 计算 avg(unitprice) 然后将它与产品的 unitprice 列进行比较。
,HAVING
根据 SQL 标准和在大多数数据库中过滤聚合后。
没有 GROUP BY
,仍然存在聚合。
但在您的情况下,您只需要一个子查询和 WHERE
:
SELECT p.*
FROM products p
WHERE p.unitprice > (SELECT AVG(p2.unitprice) FROM products p2);
,
问题来自您选择的列:
SELECT *
和
SELECT 1
与在每一行计算的普通函数不同,聚合函数是在处理整个数据集后计算的,这意味着理论上(至少没有 GROUP BY 语句),您不能同时选择聚合函数和常规函数相同的列集(即使某些 DBMS 仍然容忍这一点)。
考虑 SUM() 时更容易看到。在返回所有行之前,您不应该访问列的总数,例如,这会阻止您编写 SELECT price,SUM(price)
之类的内容。
GROUP BY
现在使您能够根据给定的条件(实际上是一堆列)重新组合行,这使得这些聚合函数在每个组的末尾而不是整个数据集。因此,由于 GROUP BY
中指定的所有列对于给定组都应该是相同的,因此您可以将它们包含在全局 SELECT
语句中。
这将我们引向实际的失败原因:在第一次查询时,您选择了所有列。在第二个中,您选择 none:仅选择常量 1
,它不是表本身的一部分。