mysql查询执行顺序为from→on→join→where→group by→having→select→order by→limit;on影响join匹配,where过滤结果集;null需用is null判断;group by非聚合字段须全部列出;having用于过滤分组结果且可引用聚合函数。

MySQL 查询语句不是靠死记语法,而是靠理解 WHERE、JOIN 和执行顺序——写错的地方,90% 出现在 ON 和 WHERE 混用、NULL 判断遗漏、或 GROUP BY 字段不全上。
SELECT 基本结构和执行顺序为什么必须搞清
很多人以为 SELECT 是从左往右执行的,其实 MySQL 实际执行顺序是:FROM → ON → JOIN → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。这个顺序直接决定你能用什么、不能用什么。
-
WHERE里不能用SELECT中定义的别名(比如SELECT price * 1.1 AS final_price WHERE final_price > 100会报错) -
ON条件只影响 JOIN 的匹配逻辑,WHERE条件则是在 JOIN 完成后过滤整行——左连接时放错位置会导致丢失 NULL 行 -
GROUP BY后,SELECT中所有非聚合字段都必须出现在GROUP BY列表里(否则在严格模式下直接报错ERROR 1055)
WHERE 和 HAVING 的区别到底在哪
WHERE 过滤的是“行”,HAVING 过滤的是“组”。它们不是可互换的替代品,选错就查不到想要的结果。
- 想查“订单金额大于 500 的用户”,用
WHERE order_amount > 500 - 想查“平均订单金额大于 500 的用户”,必须用
GROUP BY user_id+HAVING AVG(order_amount) > 500 -
HAVING可以引用聚合函数(COUNT()、AVG()等),WHERE不可以 -
HAVING性能通常更差——它是在分组后才计算,数据量已缩小但计算开销更大
LEFT JOIN 中 ON 和 WHERE 放条件的后果完全不同
这是线上最常引发数据缺失的坑。举个例子:查所有用户及其最近一笔订单,但有些用户没下单。
SELECT u.id, u.name, o.order_no FROM user u LEFT JOIN `order` o ON u.id = o.user_id AND o.status = 'paid'
上面写法能保留所有用户,未下单或订单非 paid 的用户,o.order_no 为 NULL;但如果把条件挪到 WHERE:
SELECT u.id, u.name, o.order_no FROM user u LEFT JOIN `order` o ON u.id = o.user_id WHERE o.status = 'paid'
结果只剩下了有 paid 订单的用户——LEFT JOIN 彻底退化成 INNER JOIN。
-
ON后的条件决定“哪些右表记录能连上来” -
WHERE后的条件是对最终结果集做筛选,NULL值在=判断中永远为 false - 要过滤右表,优先放
ON;要全局过滤(含左表字段),才用WHERE
NULL 值处理不当会让查询结果静默出错
MySQL 中 NULL 不等于任何值,包括它自己。所以 WHERE status != 'done' 不会命中 status IS NULL 的行,很容易漏数据。
- 判断空值必须用
IS NULL或IS NOT NULL,不能用= NULL - 聚合函数如
COUNT(col)会自动忽略NULL,但COUNT(*)统计所有行 - 排序时
ORDER BY col DESC默认把NULL排在最前(升序则在最后),需要显式控制用ORDER BY col DESC, col IS NULL - 连接字段含
NULL时,ON a.id = b.id永远不匹配,建议提前用COALESCE(a.id, 0)或补默认值
真正难的不是写出语法正确的 SELECT,而是预判数据里有没有 NULL、JOIN 后会不会产生意料外的空行、GROUP BY 是否覆盖了所有非聚合字段——这些地方一松懈,查出来的数看着对,其实已经错了。










