= null永远不生效,sql里判断空值必须用is null或is not null,因为null是缺失标记而非值,任何=比较均返回unknown,而where只保留true结果。

WHERE条件里用IS NULL还是= NULL?
直接说结论:= NULL永远不生效,SQL里判断空值必须用IS NULL或IS NOT NULL。这是因为NULL在SQL中不是值,而是“缺失值”的标记,任何与NULL的等值比较(包括=、!=、)结果都是UNKNOWN,而WHERE只保留TRUE的结果。
常见错误现象:
- 写
WHERE column = NULL——查不到任何记录,哪怕该列全是NULL - 写
WHERE column != 'abc'——会漏掉column为NULL的行,因为NULL != 'abc'不返回TRUE
过滤非空字符串但允许空格或空字符串?
IS NOT NULL只管是否为NULL,不管内容。如果字段是VARCHAR类型,可能存的是NULL、空字符串''、或纯空格' '——这三者在业务上常都被视为“空”,但SQL要分开处理。
实操建议:
- 排除
NULL和空字符串:WHERE column IS NOT NULL AND column != '' - 再排除纯空白(兼容MySQL/PostgreSQL):
WHERE column IS NOT NULL AND TRIM(column) != '' - 注意
TRIM()在SQL Server里叫RTRIM(LTRIM(column)),SQLite里支持TRIM()但不支持多字符裁剪
联合索引下IS NULL能走索引吗?
可以,但有前提。大多数主流数据库(PostgreSQL、MySQL 8.0+、SQL Server)对IS NULL支持索引查找,前提是该列为索引的一部分且未被前置列的IS NULL条件“截断”。
举个例子:有联合索引(status, created_at),以下查询能用上索引:
WHERE status = 'active' AND created_at IS NULL
但这个不行:
WHERE status IS NULL AND created_at > '2023-01-01'
因为status IS NULL无法定位索引前缀范围,优化器大概率退化为索引扫描甚至全表扫描。
性能提示:
- 单独查
IS NULL时,单列索引比联合索引更可靠 - PostgreSQL中可建表达式索引:
CREATE INDEX idx_on_null ON table ((col IS NULL)),专用于加速IS NULL查询
LEFT JOIN后怎么安全地过滤右表的空值?
这是最容易出错的场景。很多人写:
SELECT * FROM orders o LEFT JOIN customers c ON o.customer_id = c.id WHERE c.name IS NULL
看起来想查“没关联到客户”的订单,但实际会把所有c.name为NULL的行都过滤掉——包括右表根本没匹配上的行(这时c.name确实是NULL),也包括右表匹配上了但c.name字段本身就为NULL的行。
真正意图通常是“右表未匹配”,应改用:
WHERE c.id IS NULL
理由:c.id是右表主键或关联字段,只要没匹配上就必为NULL;而c.name即使匹配上了也可能为空,不能代表连接失败。
关键点:
- 用
IS NULL判断连接结果时,优先选关联字段(如c.id、c.customer_id),而非业务字段 - 如果右表允许关联字段本身为
NULL(极少见),那就得加额外条件或改用NOT EXISTS
空值逻辑不是“没有值”,而是“值未知”——这个语义差异会渗透到JOIN、GROUP BY、聚合函数甚至UNION的行为里。每次写IS NULL前,先想清楚你到底要排除“缺失”,还是“无效内容”,或是“连接失败”。










