为什么此代码能够在 HAVING 中使用来自 SELECT 的别名?

Why is this code able to use an alias from SELECT in HAVING?

我在网上找到这个解决方案 HackerRank problem:

SELECT c.hacker_id, h.name, COUNT(c.challenge_id) AS cnt 
FROM Hackers AS h 
JOIN Challenges AS c ON h.hacker_id = c.hacker_id
GROUP BY c.hacker_id, h.name 
HAVING
    cnt = (SELECT COUNT(c1.challenge_id) FROM Challenges AS c1 GROUP BY c1.hacker_id ORDER BY COUNT(*) DESC LIMIT 1) OR
    cnt NOT IN (SELECT COUNT(c2.challenge_id) FROM Challenges AS c2 GROUP BY c2.hacker_id HAVING c2.hacker_id <> c.hacker_id)
ORDER BY cnt DESC, c.hacker_id;

可以看到,cnt定义在SELECT中,然后在HAVING中使用。我的理解是,从逻辑上讲,GROUP BY and HAVING 运行 before SELECT。因此,我希望 SQL 在执行 GROUP BY 时不会识别 cnt,并抛出错误。但是,代码给出了正确的解决方案。

谁能解释一下为什么?也许 MySQL 人为地纠正了这个问题?

您假设 SELECT 子句中定义的别名不能在 HAVING 子句中使用 通常 正确:这在标准 SQL(也称为 ANSI SQL),大多数数据库不允许这样。

然而,MySQL 扩展了标准,如解释的那样 in the documentation:

The MySQL extension permits the use of an alias in the HAVING clause for the aggregated column.

所以您显示的代码不是有效的 ANSI SQL,但它是一个有效的 MySQL 查询。 MySQL 实现了对 ANSI SQL 的许多其他扩展,并在链接文档中进行了描述。

更一般地说,据我所知,没有一个数据库是完全严格遵守ANSI规范的。它们都缺少功能和扩展。学习 SQL,您还需要了解您所使用的数据库的特性 运行。