SQL 中 IS 与 = 的区别:一个 NULL 值引发的思考
为什么查询结果总是少一条数据?可能是 NULL 在捣鬼
在 SQL 查询中,很多开发者都曾遇到过这样的困惑:明明看起来正确的查询语句,返回的结果却总是与预期不符。这往往是因为没有正确理解 IS
和 =
操作符的区别,特别是当遇到 NULL 值时。
一、核心区别:一句话总结
=
用于比较值 ,IS
用于比较NULL(或布尔常量)。
二、IS 与 = 的适用场景
三、详细对比表格
特性 | = 操作符 |
IS 操作符 |
---|---|---|
主要用途 | 普通值比较 | NULL 值比较 |
与 NULL 比较 | 总是返回 UNKNOWN | 正确返回 TRUE/FALSE |
与非 NULL 值比较 | 正常工作 | 可能语法错误或逻辑错误 |
布尔值比较 | 支持(= TRUE/FALSE) | 部分数据库支持(IS TRUE/FALSE) |
可读性 | 常规比较,直观 | 专门用于 NULL,意图明确 |
三值逻辑处理 | 需要特别注意 NULL | 专门为 NULL 设计 |
四、NULL 比较的陷阱与实际示例
错误示例
sql
-- 这行代码永远返回空结果集!
SELECT * FROM users WHERE deleted_at = NULL;
正确示例
sql
-- 正确查找未删除的用户
SELECT * FROM users WHERE deleted_at IS NULL;
五、为什么 NULL 如此特殊?
NULL 在 SQL 中表示"未知"或"不存在"的值,它不等于任何值,甚至不等于它自己。这就是为什么不能使用 =
比较 NULL 的原因。
SQL 使用三值逻辑:
- TRUE(真)
- FALSE(假)
- UNKNOWN(未知)
任何与 NULL 的比较都会返回 UNKNOWN,而 WHERE 子句只返回条件为 TRUE 的行。
六、NOT IN 子查询中的 NULL 陷阱
问题代码
sql
SELECT *
FROM customers
WHERE customers.id NOT IN (
SELECT customerid FROM orders
);
问题分析
如果 orders 表中的 customerid 包含 NULL 值,上述查询将返回空结果集,因为:
x NOT IN (1, 2, NULL)
等价于 x <> 1 AND x <> 2 AND x <> NULL
而 x <> NULL
的结果是 UNKNOWN,导致整个表达式为 UNKNOWN,最终被视为 FALSE。
解决方案
使用 NOT EXISTS 替代 NOT IN:
sql
SELECT *
FROM customers c
WHERE NOT EXISTS (
SELECT 1
FROM orders o
WHERE o.customerid = c.id
);
七、不同数据库的差异说明
数据库 | IS 布尔值支持 | = 布尔值支持 | 建议 |
---|---|---|---|
MySQL | 支持 (IS TRUE/IS FALSE) | 支持 (= TRUE/= FALSE) | 统一使用 = |
PostgreSQL | 支持 | 支持 | 统一使用 = |
SQL Server | 不支持 | 支持 | 使用 = |
SQLite | 有限支持 | 支持 | 使用 = |
八、实际工作中的应用建议
- NULL 检查一律使用 IS NULL 或 IS NOT NULL
- 布尔值比较统一使用 = 操作符(保持代码一致性)
- 避免在 NOT IN 子查询中包含 NULL 值
- 优先使用 NOT EXISTS 而不是 NOT IN(避免 NULL 问题)
- 在复杂查询中显式处理 NULL(使用 COALESCE 或 ISNULL 函数)
九、记忆口诀
NULL 用 IS,非 NULL 用 =
布尔两者都可以,统一风格最重要
NOT IN 里有陷阱,NOT EXISTS 更可靠
总结
理解 IS
和 =
的区别是编写正确 SQL 查询的基础。关键是要记住 NULL 的特殊性------它表示未知值,不能使用常规的比较操作符。掌握了这个概念,你就能避免许多常见的 SQL 陷阱,写出更加健壮和可靠的查询语句。
下次当你发现查询结果与预期不符时,不妨先检查一下:是不是 NULL 值在捣鬼?是不是应该用 IS 而不是 =?