HAVING执行顺序早于SELECT为何可引用SELECT中定义的count别名
问题解答
你查到的HAVING执行顺序早于SELECT是标准SQL的通用执行逻辑,通用执行顺序规则如下:
- FROM 阶段:加载语句涉及的所有数据表
- WHERE 阶段:过滤行级基础数据
- GROUP BY 阶段:按指定字段对数据分组
- HAVING 阶段:对分组后的结果做聚合过滤
- SELECT 阶段:计算需要返回的列、定义列别名
- ORDER BY 阶段:对最终返回结果排序
按照这个标准逻辑,HAVING执行时SELECT阶段还未运行,自然不可能识别SELECT里定义的别名,如果你把示例SQL放到PostgreSQL、SQL Server、Oracle等严格遵守SQL标准的数据库中运行,会直接报错提示count列不存在。
你写的语句能正常执行,是因为你使用的是MySQL数据库,它单独做了非标准的语法扩展,允许HAVING子句提前引用SELECT列表中定义的别名,甚至是聚合函数的别名,属于MySQL为了简化开发做的特性兼容,不属于SQL通用规则,不可以套用到所有数据库场景中。
你给出的示例是MySQL下的合法写法:
SELECT `title`, (SELECT COUNT(*) FROM `comments` WHERE `post_id` = `posts`.`id`) as `count` FROM `posts` HAVING `count` != 0
如果需要写兼容所有数据库的标准写法,可以参考两种方案:
-- 方案1:重复子查询逻辑,不使用别名判断 SELECT `title`, (SELECT COUNT(*) FROM `comments` WHERE `post_id` = `posts`.`id`) as `count` FROM `posts` WHERE (SELECT COUNT(*) FROM `comments` WHERE `post_id` = `posts`.`id`) != 0 -- 方案2:嵌套子查询,外层用WHERE过滤 SELECT * FROM ( SELECT `title`, (SELECT COUNT(*) FROM `comments` WHERE `post_id` = `posts`.`id`) as `count` FROM `posts` ) t WHERE `count` != 0
内容的提问来源于stack exchange,提问作者Neumann-Kohai
相关产品推荐
相关产品推荐

