我惊讶地发现以下工作:
SELECT name, height * weight as inchpounds
FROM sashelp.class
HAVING inchpounds > 5000;
因为我认为 HAVING 子句是在 SELECT 子句之前严格处理的。这实际上是我的错误假设吗?或者这是 SAS 的 SQL 实现所特有的?
严格来说,如果我没记错的话,SQL 标准的defineHAVING
子句要在SELECT
子句之前处理。因此,在 SELECT 中定义的别名不能在HAVING
子句中使用。
请参阅我在相关问题中的回答:在 where 子句中使用“case expression column”来获取处理语句的顺序SELECT
,即:
FROM -> WHERE -> GROUP BY -> HAVING -> SELECT -> ORDER BY
因此,在大多数 SQL 实例中,该查询将产生错误。MySQL 是我知道的一个例外,它允许偏离标准(并且在子句中SELECT
也允许使用别名)。GROUP BY
正如评论中提到的@a_horse_with_no_name,查询在大多数 SQL 产品中也会因为另一个原因而失败:HAVING
没有意味着所有行都存在聚合,因此在 the和子句GROUP BY
中只允许聚合函数。HAVING
SELECT
查看SAS SQL 文档和示例后,您在上面发布的查询似乎在 SAS SQL 中有效,并按以下方式执行(在标准 SQL 中):
SELECT name, height * weight AS inchpounds
FROM sashelp.class
WHERE height * weight > 5000;
如果我理解正确,您也可以将聚合函数与非聚合列混合,如下所示:
SELECT name, height,
MAX(height) AS max_height
FROM sashelp.class ;
这将被评估为(在标准 SQL 中):
SELECT name, height,
MAX(height) OVER () AS max_height
FROM sashelp.class ;
SQL 标准指定解释子句的顺序,而不是它们的执行顺序。实际上,这意味着having
子句在 之后进行解析select
,因此它们可以使用select
语句中定义的变量。SAS SQL 与其他方言不同。您可以在子句中使用select
变量。where
SQL 引擎可以根据自己的喜好自由地实际运行查询。但是,您的问题不是关于运行查询,而是关于解析它。
使用having
不带 a 的子句group by
通常是值得怀疑的。但是,我相信它应该适用于任何方言。唯一的问题是返回 0 行还是 1 个摘要行。
您的特别查询有效是令人惊讶的。在大多数 SQL 方言中,您会收到错误消息,因为该having
子句将暗示聚合,而 中的值select
不在聚合函数中。唯一可行的其他方言是 MySQL,因为它有一个(错误)功能,称为隐藏列。与其他方言相比,SAS SQL 与标准 SQL 有点远。
我不能说 SQL“标准”,但就 SAS 实现而言,WHERE
和HAVING
子句之间的唯一区别是“何时”应用它们。 WHERE
子句适用于创建中间结果(构建包含语句中列出的列的临时表SELECT
),HAVING
子句控制将哪些行写入最终表。
或者,可以在语句中使用CALCULATED
关键字:WHERE
SELECT name, height * weight as inchpounds
FROM sashelp.class
WHERE CALCULATED inchpounds > 5000;
这实际上是我的错误假设吗?
它可能是假的。查询计划器将根据数据库拥有的数据和统计信息来决定如何运行查询。
考虑以特定顺序运行的不同子句有助于编写和推理查询,但这并不是大多数 SQL 数据库的实际工作方式。