这节课我们会更深入地认识一下神秘的 NULL。当然,你以后自己踩坑的机会还多着呢,不过……提前知道总没坏处。我们来看看几个和 NULL 有关的典型错误。
错误1:用普通的 = 操作符判断 NULL
SQL 新手最常见的错误之一,就是想用 = 操作符判断某个值是不是 NULL。
会发生什么?
SELECT *
FROM students
WHERE age = NULL;
你可能以为这样能查出所有年龄未知的学生,但其实啥也查不出来。为啥?因为 NULL 不是一个具体的值,普通的比较操作符对它没用。就像 SQL 魔法书里说的:“NULL 不能直接比较”。
正确做法?
要判断是不是 NULL,得用 IS NULL:
SELECT *
FROM students
WHERE age IS NULL;
这样你就能查到所有没有填写年龄的学生了。
错误2:聚合函数会忽略 NULL(除了 COUNT(*))
用聚合函数查询时,NULL 会自动被排除在计算之外。这有时候会让结果很迷惑。
会发生什么?
SELECT AVG(salary) AS avg_salary
FROM employees;
如果 salary 这一列有 NULL,这些行会被直接忽略,平均工资就不会算进去这些记录。这样可能会让你对平均工资有误解。
怎么避免?
聚合前,记得把 NULL 替换成默认值。比如用 COALESCE():
SELECT AVG(COALESCE(salary, 0)) AS avg_salary
FROM employees;
这样 NULL 会先变成 0 再参与计算。
错误3:拿 NULL 互相比
在数据库里,NULL 跟任何东西都不相等,哪怕是另一个 NULL。这点很容易让人懵。
会发生什么?
SELECT *
FROM students
WHERE NULL = NULL;
这个查询也会返回空结果。为啥?因为 SQL 觉得一个“没有值”不能等于另一个“没有值”。SQL 真的很哲学。
正确做法?
如果你想判断两个 NULL 是否“都为 NULL”,要用 IS NULL 这种写法。比如:
SELECT *
FROM students
WHERE first_name IS NULL AND last_name IS NULL;
错误4:除以 NULL
用 NULL 做除数,不只是个错误,简直是数学犯罪,SQL 会直接给你一个 NULL 作为“惩罚”。
会发生什么?
SELECT 10 / NULL AS result;
结果?NULL。SQL 直接懒得理你想干啥。
怎么避免?
想让你的查询更安全,可以用 COALESCE() 或 NULLIF():
SELECT 10 / COALESCE(divisor, 1) AS result
FROM calculations;
这样如果 divisor 是 NULL,就会用 1 来除。
错误5:逻辑操作符遇到 NULL 就罢工
NULL 一旦出现在逻辑表达式里,逻辑就崩了。比如 TRUE AND NULL 会返回 NULL,不是 TRUE 也不是 FALSE。
会发生什么?
SELECT *
FROM students
WHERE age > 18 OR age = NULL;
这种情况下,即使 age > 18 对某些行成立,有 age 为 NULL 的行也可能被排除。为啥?因为 age = NULL 这部分会返回 NULL,不是 TRUE。
正确做法?
逻辑条件里一定要显式处理 NULL:
SELECT *
FROM students
WHERE age > 18 OR age IS NULL;
错误6:排序 NULL 时的“隐形”行为(最容易踩的大坑)
用 ORDER BY 排序时,NULL 的表现可能让你很意外。默认情况下,PostgreSQL 升序时 NULL 在最后,降序时 NULL 在最前。
会发生什么?
SELECT product_name, price
FROM products
ORDER BY price;
如果 price 有 NULL,这些行会排在最后。
怎么避免意外?
你可以用 NULLS FIRST 或 NULLS LAST 明确指定 NULL 的排序:
SELECT product_name, price
FROM products
ORDER BY price NULLS FIRST;
错误7:外键和 NULL 配合时的奇怪表现
外键字段里有 NULL,有时候会让你觉得很迷。
会发生什么?
如果你在表里加了外键,然后插入一行时外键字段留空,PostgreSQL 会啥反应都没有。这是因为 NULL 不会去检查关联表的匹配。
正确用法?
如果你不想让这些字段出现 NULL,就加上 NOT NULL 限制。或者你得知道,NULL 的外键其实就是“孤儿”,不属于任何关联表。
关于关联表和外键的更多内容,下节课见 :P
GO TO FULL VERSION