[一、什么是 NULL?](#一、什么是 NULL?)
[二、为什么 = NULL 不起作用?](#二、为什么 = NULL 不起作用?)
[三、MySQL 处理 NULL 的三大核心工具](#三、MySQL 处理 NULL 的三大核心工具)
[四、NULL 在聚合函数中的行为](#四、NULL 在聚合函数中的行为)
[五、NULL 在排序中的表现](#五、NULL 在排序中的表现)
[六、PHP 脚本中处理 NULL](#六、PHP 脚本中处理 NULL)
[七、设计建议:何时允许 NULL?](#七、设计建议:何时允许 NULL?)
前言
在 MySQL 数据库开发中,NULL 是一个特殊且容易被误解的值。它不代表"空字符串"或"0",而是表示缺失、未知或不适用的数据。许多开发者因对 NULL 的处理不当,导致查询结果不符合预期,甚至引发逻辑错误。本文将系统讲解 MySQL 中 NULL 的特性、常见误区以及正确处理方法。
一、什么是 NULL?
- NULL ≠ 空字符串('')
- NULL ≠ 数字 0
- NULL 表示"没有值"或"值未知"
例如:
- 用户未填写电话号码 →
phone = NULL - 商品尚未定价 →
price = NULL - 员工尚未分配部门 →
department_id = NULL
注意:
任何与 NULL 的比较(包括= NULL、!= NULL、< NULL等)结果都是UNKNOWN(在布尔上下文中视为FALSE)。
二、为什么 = NULL 不起作用?
这是最常见的误区!
sql
-- 错误写法:永远返回空结果集
SELECT * FROM yuming_test_tbl WHERE yuming_count = NULL;
-- 同样无效
SELECT * FROM yuming_test_tbl WHERE yuming_count != NULL;
原因分析:
在 SQL 三值逻辑中,NULL = NULL 的结果是 NULL(未知) ,而非 TRUE。因此,WHERE 子句不会将其视为匹配条件。
正确做法 :使用专用运算符 IS NULL 和 IS NOT NULL。
sql
-- 查找 NULL 值
SELECT * FROM yuming_test_tbl WHERE yuming_count IS NULL;
-- 查找非 NULL 值
SELECT * FROM yuming_test_tbl WHERE yuming_count IS NOT NULL;
三、MySQL 处理 NULL 的三大核心工具
1. IS NULL / IS NOT NULL ------ 判断是否为 NULL
用于 WHERE、HAVING 等条件判断。
sql
-- 示例:找出未分配部门的员工
SELECT name FROM employees WHERE department_id IS NULL;
-- 示例:统计有薪资记录的员工数
SELECT COUNT(*) FROM employees WHERE salary IS NOT NULL;
2. <=> 安全等于操作符(NULL-safe equality)
这是 MySQL 特有的NULL 安全比较符 ,即使两边都是 NULL,也返回 TRUE。
| 表达式 | 结果 |
|---|---|
NULL <=> NULL |
1(TRUE) |
'A' <=> 'A' |
1 |
'A' <=> NULL |
0(FALSE) |
5 <=> 5 |
1 |
sql
-- 查找 commission 为 NULL 的员工(等价于 IS NULL)
SELECT * FROM employees WHERE commission <=> NULL;
-- 在 JOIN 中安全比较(避免因 NULL 导致漏连)
SELECT * FROM t1 JOIN t2 ON t1.id <=> t2.ref_id;
💡 适用于需要将 NULL 视为"相等"的场景,如数据比对、去重等。
3. 替换 NULL 值的函数
(1) IFNULL(expr1, expr2)
- MySQL 特有;
- 若
expr1为 NULL,返回expr2;否则返回expr1。
sql
-- 将 NULL 阅读量显示为 0
SELECT yuming_author, IFNULL(yuming_count, 0) AS views
FROM yuming_test_tbl;
(2) COALESCE(value1, value2, ..., valueN)
- 标准 SQL 函数,兼容性更好;
- 返回参数列表中第一个非 NULL 的值。
sql
-- 多级备用值:优先用手机,其次邮箱,最后"未提供"
SELECT name, COALESCE(phone, email, '未提供') AS contact
FROM users;
在跨数据库项目中优先使用
COALESCE。
四、NULL 在聚合函数中的行为
大多数聚合函数会自动忽略 NULL 值:
| 函数 | 对 NULL 的处理 |
|---|---|
COUNT(*) |
统计所有行(含 NULL) |
COUNT(column) |
仅统计非 NULL 行 |
SUM(), AVG(), MAX(), MIN() |
忽略 NULL |
sql
-- 示例表:salaries = [1000, 2000, NULL, 3000]
SELECT COUNT(*) -- 结果: 4(总行数)
SELECT COUNT(salary) -- 结果: 3(非 NULL 行数)
SELECT AVG(salary) -- 结果: 2000((1000+2000+3000)/3)
若希望将 NULL 视为 0 参与计算:
sql
-- 计算平均薪资(NULL 视为 0)
SELECT AVG(IFNULL(salary, 0)) AS avg_salary FROM employees;
五、NULL 在排序中的表现
默认情况下:
- 升序(ASC):NULL 排在最前(MySQL 8.0+ 可控);
- 降序(DESC):NULL 排在最后。
但可通过 NULLS FIRST / NULLS LAST 显式控制(MySQL 8.0.16+):
sql
-- 将 NULL 价格排在最后
SELECT product_name, price
FROM products
ORDER BY price ASC NULLS LAST;
-- 将 NULL 日期排在最前
SELECT title, publish_date
FROM articles
ORDER BY publish_date DESC NULLS FIRST;
低版本 MySQL 可通过
ORDER BY ISNULL(price), price模拟。
六、PHP 脚本中处理 NULL
在 PHP 中,需根据变量是否为 null 动态构建 SQL:
php
<?php
$conn = mysqli_connect('localhost', 'root', '123456');
mysqli_query($conn, "SET NAMES utf8mb4");
mysqli_select_db($conn, 'YUMING');
// 假设 $count 来自用户输入或配置
$count = $_GET['count'] ?? null; // 可能为 null
if ($count !== null) {
// 注意:此处应使用预处理防止注入!
$sql = "SELECT * FROM yuming_test_tbl WHERE yuming_count = " . (int)$count;
} else {
$sql = "SELECT * FROM yuming_test_tbl WHERE yuming_count IS NULL";
}
$result = mysqli_query($conn, $sql);
while ($row = mysqli_fetch_assoc($result)) {
echo "{$row['yuming_author']} - {$row['yuming_count']}\n";
}
mysqli_close($conn);
?>
建议 :实际项目中必须使用 预处理语句 (
mysqli_prepare)避免 SQL 注入。
七、设计建议:何时允许 NULL?
| 场景 | 是否允许 NULL | 建议 |
|---|---|---|
| 必填字段(如用户名) | ❌ 否 | 设为 NOT NULL |
| 可选信息(如备注、中间名) | ✅ 是 | 允许 NULL |
| 数值型统计字段 | ⚠️ 谨慎 | 考虑默认值 0 vs NULL |
| 外键字段 | ⚠️ 视业务而定 | 若"可无关联",则允许 NULL |
建议:
- 明确字段语义,避免滥用 NULL;
- 在应用层统一处理 NULL,保持业务逻辑清晰。
小结
判空不用等号比,
IS NULL才是真理;
替换空值用IFNULL,多备选项COALESCE;
聚合自动跳 NULL,排序位置要留意;
安全等于<=>记,设计表时慎用 NULL!
掌握 NULL 的正确处理方式,不仅能避免查询陷阱,还能提升数据质量和系统健壮性。在数据库世界里,理解 NULL,就是理解"未知"的艺术。