SQL - 使用“HAVING”和“EXISTS”而不使用“GROUP BY”

问题描述

不允许在没有“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,它不是表本身的一部分。