游乐游手机版
首页/数据库/文章详情

数据库里最反直觉的陷阱:NULL不等于空,90%新手踩过坑

时间:2026-07-07 07:09
NULL是数据库中表示“未知”的特殊标记,而非空值或0。它引入三值逻辑,导致用=NULL查不出数据、COUNT(column)忽略NULL、运算结果全为NULL、NOTIN遇NULL返回空、排序位置因数据库而异。正确处理需用ISNULL判断、COALESCE赋默认值、NOTEXISTS替代NOTIN,建表时尽量设置NOTNULL。

数据库里有个设计,让无数新手在深夜怀疑人生——NULL。

你可能以为NULL就是空、就是什么都没有、就是空白。但数据库爸爸会告诉你:WHERE column = NULL?不好意思,一条数据都查不出来。你以为COUNT(*)能统计所有行,结果COUNT(column)悄悄漏掉了一堆。你写了个if(value == null)的判断,数据死活对不上——道理都懂,可它就是跟你作对。

一切的根源在于——NULL在数据库里,压根不是空值,而是一个特殊标记,表示“未知”或“不适用”。

今天就把它彻底讲清楚,帮你把这些反直觉的坑一个个填上。


几个先搞明白的概念

NULL的本质:NULL不是空字符串'',不是0,不是false。它是一个独立的特殊值,表示“这个字段当前没有确定的值”。你可以把它想象成一张问卷上的“未作答”——不是“否”,也不是“空白”,而是“我不知道”。

三值逻辑:大多数编程语言只有TRUE和FALSE两种结果。但NULL一掺和进来,逻辑运算就变成了三值:TRUE、FALSE、UNKNOWN。涉及NULL时,结果很可能就是UNKNOWN。而WHERE条件只返回TRUE的行,UNKNOWN被当作FALSE处理,这就是为什么很多查询“查不出数据”的根本原因。

空字符串 vs NULL:空字符串''是一个确定的值——它就是一个长度为0的字符串。NULL表示“没有值”。''和NULL在数据库里是两码事,千万别混为一谈。


NULL的五大反直觉陷阱

陷阱一:WHERE column = NULL 查不出任何数据

新手必踩,没跑。

-- 你以为这样能查出所有phone为空的记录
SELECT * FROM users WHERE phone = NULL;
-- 结果:0行

-- 正确写法
SELECT * FROM users WHERE phone IS NULL;

为什么?因为NULL不等于任何东西,包括它自己。在数据库中:

NULL = NULL  →  UNKNOWN(不是TRUE)
NULL != NULL →  UNKNOWN(不是TRUE)

NULL = NULL的结果是UNKNOWN,而WHERE只认TRUE,所以查出来0行。必须用IS NULLIS NOT NULL来判断。

陷阱二:COUNT(column) 忽略NULL值

-- 假设users表有100行,其中10行phone为NULL
SELECT COUNT(*) FROM users;     -- 100(统计所有行)
SELECT COUNT(phone) FROM users; -- 90(忽略NULL值)

COUNT(*)统计行数,不管字段是什么。COUNT(column)只看该字段非NULL的行数。如果你想知道“有多少人有手机号”,用COUNT(phone);如果你想知道“总共有多少人”,用COUNT(*)。

陷阱三:NULL参与运算,结果还是NULL

SELECT 1 + NULL;        -- NULL
SELECT 'hello' || NULL; -- NULL
SELECT NULL = 0;        -- UNKNOWN(不是FALSE)
SELECT NULL = '';       -- UNKNOWN(不是FALSE)
SELECT NULL AND TRUE;   -- UNKNOWN(不是FALSE)

任何值和NULL运算,结果都是NULL。这在业务代码里会埋下不少隐形冲击波:

-- 计算员工总薪资
SELECT salary + bonus FROM employees;
-- 如果某个员工bonus是NULL,整条记录的总薪资就是NULL

正确做法是用COALESCE把NULL替换为默认值:

SELECT salary + COALESCE(bonus, 0) FROM employees;
-- NULL变成0,计算正常

陷阱四:NOT IN 遇到NULL,整个查询结果为空

这个最隐蔽,杀伤力也最大。

-- 假设子查询返回了 (1, 2, NULL)
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM orders);

-- 如果orders表里有user_id为NULL的记录,整个查询返回0行

为什么?因为NOT IN在底层展开成:

WHERE id != 1 AND id != 2 AND id != NULL

id != NULL的结果是UNKNOWN,整个AND表达式变成UNKNOWN,WHERE就不返回任何行了。

解决办法:用NOT EXISTS替代NOT IN,或者在子查询中排除NULL:

-- 方案一:NOT EXISTS
SELECT * FROM users u WHERE NOT EXISTS (
    SELECT 1 FROM orders o WHERE o.user_id = u.id
);

-- 方案二:子查询排除NULL
SELECT * FROM users WHERE id NOT IN (
    SELECT user_id FROM orders WHERE user_id IS NOT NULL
);

陷阱五:排序时NULL的位置

不同数据库对NULL的处理方式不一样:

SELECT * FROM users ORDER BY phone ASC;
-- MySQL:NULL排在最前面
-- Oracle/PostgreSQL:NULL排在最后面

如果不确定数据库的默认行为,最好显式指定:

-- PostgreSQL
SELECT * FROM users ORDER BY phone ASC NULLS FIRST;
SELECT * FROM users ORDER BY phone DESC NULLS LAST;

-- MySQL(用IF/CASE处理)
SELECT * FROM users ORDER BY IF(phone IS NULL, 1, 0), phone ASC;

NULL的正确打开方式

判断NULL:用IS NULLIS NOT NULL,别用=!=

处理NULL参与计算:用COALESCE提供默认值。

SELECT COALESCE(phone, '未登记') FROM users;
SELECT salary + COALESCE(bonus, 0) FROM employees;

聚合函数对NULL的态度

函数 对NULL的处理
COUNT(*) 统计所有行,不忽略NULL
COUNT(column) 忽略该列的NULL值
SUM(column) 忽略NULL值
A VG(column) 忽略NULL值,且分母也不计NULL行
MAX/MIN 忽略NULL值
GROUP BY NULL值被分到同一组

避免NULL的设计思路

如果业务上某个字段“必须有值”,建表时就加上NOT NULL约束,并设置默认值:

CREATE TABLE users (
    id INT PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    status TINYINT NOT NULL DEFAULT 0,
    phone VARCHAR(20)  -- 允许NULL,因为确实可能没登记
);

NOT NULL的字段就别留NULL。NULL存在的每一处,都是未来查询时可能踩的坑。


总结

NULL不是空值,是“未知”。记住三句话:

  1. 判断NULL用IS NULL,别用=
  2. NULL参与运算结果是NULL,用COALESCE处理
  3. NOT IN遇到NULL会吞掉所有结果,改用NOT EXISTS

建表时能NOT NULL就别留NULL,少一个NULL,少十个bug。

来源:https://juejin.cn/post/7658072876424233014
上一篇Qwen大模型生成MySQL性能优化量化对比报告测评 下一篇Qwen大模型助力MySQL敏感数据脱敏与隐私保护
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
用Qwen大模型为MySQL查询推荐最佳可视化图表
数据库 · 2026-07-07

用Qwen大模型为MySQL查询推荐最佳可视化图表

如何用Qwen大模型为MySQL查询自动推荐最佳可视化图表 你是否希望从MySQL查出的销售数据自动生成柱状图,而不是对着满屏数字发呆?刚写完一条SELECT语句,却不确定该使用折线图还是热力图来展示时间趋势?或者你把查询结果复制进Excel后才想起,其实散点图更能说明问题。这些场景是不是很熟悉?

MongoDB 4.0事务处理机制底层原理详解
数据库 · 2026-07-07

MongoDB 4.0事务处理机制底层原理详解

MongoDB4 0多文档事务深度复用WiredTiger引擎原生多行事务能力,基于快照隔离和MVCC机制。事务启动获取clusterTime,读操作基于固定快照,写冲突在提交时检测。oplog异步刷盘可能影响持久性,生产环境需启用journal并控制事务超时。

Qwen大模型助力MySQL敏感数据脱敏与隐私保护
数据库 · 2026-07-07

Qwen大模型助力MySQL敏感数据脱敏与隐私保护

借助Qwen大模型一键生成合规的MySQL脱敏SQL语句 先看一个真实业务场景:你需要在MySQL中对姓名、手机号、身份证号这类敏感字段进行合规脱敏,且脱敏逻辑要具备可复用性、可审计性、可回溯能力。此时直接打开Qwen的Web界面或调用API,输入一条清晰指令就能搞定——例如:“请为MySQL表us

Qwen大模型生成MySQL性能优化量化对比报告测评
数据库 · 2026-07-07

Qwen大模型生成MySQL性能优化量化对比报告测评

Qwen大模型能够基于两份CSV文件,自动生成一份包含QPS、延迟等8项核心指标的MySQL优化量化对比报告。您只需导出规范的CSV数据,使用特定提示词触发解析,再将结果转为HTML或PDF格式即可交付。此外,通过三步验证流程,可确保所有数据真实可信,满足技术评审要求。需要一份能直接用于技术评审或D