SQL 中判断数据是否为空(NULL)需要特别注意以下关键事项

在 SQL 中判断数据是否为空(NULL)需要特别注意以下关键事项,这些是实际开发中最常见的陷阱:


⚠️ 核心注意事项

1. 必须使用 IS NULL / IS NOT NULL
-- ✅ 正确写法
SELECT * FROM users WHERE phone IS NULL;      -- 查空值
SELECT * FROM users WHERE phone IS NOT NULL;  -- 查非空

-- ❌ 致命错误写法(永远无效!)
SELECT * FROM users WHERE phone = NULL;       -- 错误! 
SELECT * FROM users WHERE phone != NULL;      -- 错误!

原因
NULL 代表 未知值/缺失值,在 SQL 逻辑中:

  • NULL = NULL → 结果不是 TRUE 而是 UNKNOWN
  • 任何与 NULL 的比较都返回 UNKNOWN
  • WHERE 子句只返回条件为 TRUE 的行(过滤掉 UNKNOWN
2. 聚合函数忽略 NULL 值
SELECT 
  COUNT(phone) AS not_null_count,  -- 只统计非空值
  COUNT(*) AS total_rows            -- 统计所有行(含NULL)
FROM users;
  • AVG()SUM() 等聚合函数 自动跳过 NULL
  • 例外:COUNT(*) 统计所有行(包括 NULL 值行)
3. 算术运算中的 NULL 污染
SELECT 10 + NULL;   -- 结果 → NULL
SELECT 100 / NULL;  -- 结果 → NULL

任何包含 NULL 的算术运算结果都是 NULL

4. 逻辑运算的特殊性
SELECT NULL AND TRUE;   -- 结果 → NULL
SELECT NULL OR FALSE;   -- 结果 → NULL
SELECT NOT NULL;        -- 结果 → NULL
  • 三值逻辑:TRUE/FALSE/UNKNOWNNULL 参与时可能返回 UNKNOWN

🧩 空字符串 vs NULL 的区别

特性 NULL ''(空字符串)
数据类型 表示"未知" 有效的字符串值
存储占用 无数据存储 占用存储空间(长度0)
比较结果 NULL = NULL → 未知 '' = ''TRUE
查询方式 WHERE col IS NULL WHERE col = ''

示例

INSERT INTO test VALUES (NULL), ('');

-- 区分查询:
SELECT * FROM test WHERE col IS NULL;  -- 只返回 NULL
SELECT * FROM test WHERE col = '';     -- 只返回空字符串

🛠️ 处理 NULL 的最佳实践

1. 使用安全函数
-- 将 NULL 转为默认值
SELECT COALESCE(phone, 'N/A') FROM users;  -- NULL → 'N/A'

-- 条件判断(类似三元表达式)
SELECT IFNULL(phone, '未填写') FROM users;  -- MySQL
SELECT NVL(phone, '未知') FROM employees;   -- Oracle
2. 空值检查综合方案
-- 同时检测 NULL 和空字符串
SELECT * FROM products 
WHERE COALESCE(description, '') = '';

-- 或使用
WHERE description IS NULL OR description = '';
3. 索引优化建议
  • 对频繁查询的列使用 NOT NULL 约束(可提升索引效率)
  • 避免在可空列上建立唯一索引(因唯一索引允许多个 NULL

开发中常见陷阱

陷阱1:NOT IN 子查询包含 NULL

-- 错误示例(返回空结果)
SELECT * FROM orders 
WHERE customer_id NOT IN (
  SELECT id FROM customers WHERE status = 'inactive' -- 子查询可能含 NULL
);

修正方案

SELECT * FROM orders 
WHERE customer_id NOT IN (
  SELECT id FROM customers 
  WHERE status = 'inactive' 
    AND id IS NOT NULL  -- 显式排除 NULL
);

陷阱2:连接查询的 NULL 匹配

-- 内连接会过滤掉 NULL 关联的行
SELECT * 
FROM employees e
JOIN departments d ON e.dept_id = d.id; -- dept_id 为 NULL 的员工不会出现

解决方案

-- 使用左连接保留 NULL 关联行
SELECT *
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.id;

💡 设计建议

  1. 表设计时

    • 明确列是否允许 NULL(用 NOT NULL 约束强制非空)
    • 为重要字段设置默认值(如 DEFAULT ''DEFAULT 0
  2. 查询时

    • 永远用 IS NULL 判断空值
    • 对可空列做运算时先用 COALESCE 转换
  3. 业务逻辑

    • 区分 NULL(未设置)和空字符串(用户主动清空)的业务含义