mysql如何编写查询语句_mysqlselect语法详解

来源:这里教程网 时间:2026-02-28 20:52:40 作者:

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 是否覆盖了所有非聚合字段——这些地方一松懈,查出来的数看着对,其实已经错了。

相关推荐