PostgreSQL NULL 值(详细教程)

什么是 PostgreSQL NULL 值?

在数据库的世界里,数据不是“有”就是“没有”,但“没有”这件事,其实并不简单。你可能以为“空值”就是什么都没有,但在 PostgreSQL 中,这种“空”是有特定含义的——它就是 NULL

NULL 并不是“空字符串”('')、也不是“0”或“false”,它代表的是“未知”或“缺失”的数据。你可以把它想象成一个未填写的表格字段:比如你在填写一份个人信息表,名字那栏空白,不是因为你不叫名字,而是你暂时不知道,或者没写。这个“不知道”在数据库里,就是 NULL

在 PostgreSQL 中,NULL 是一种特殊的占位符,表示某个字段的值尚未确定。它不像普通值那样可以参与运算或比较,而是有自己独特的规则。理解这一点,是掌握 PostgreSQL 数据处理的基础。


NULL 值的三大特性

不等于任何值,包括它自己

这是最容易让人踩坑的一点:NULL 不等于 NULL

-- 错误的写法:你以为这能查出所有 NULL 的数据
SELECT * FROM users WHERE age = NULL;

-- 正确的做法:必须使用 IS NULL
SELECT * FROM users WHERE age IS NULL;

💡 注释:在 SQL 中,= 运算符无法判断 NULL,因为 NULL 表示“未知”,和“未知”比,结果也是“未知”。所以必须用 IS NULLIS NOT NULL 来判断。

与 NULL 的运算结果仍是 NULL

当你对一个 NULL 值进行算术、字符串拼接等操作时,结果依然是 NULL

-- 示例:计算年龄加 10
SELECT age + 10 AS new_age FROM users;

-- 如果 age 是 NULL,结果就是 NULL,不会变成 10 或其他数字

💡 注释:这就像你手里的一个盒子,里面什么都没有。你把它和另一个盒子叠在一起,但你不知道里面有没有东西,最终结果也只能是“未知”——这就是 NULL 的“传染性”。

比较运算符无法判断 NULL

你不能用 =, <>, >, < 来判断 NULL,因为这些操作的结果是 UNKNOWN,而不是 TRUEFALSE

-- 错误示例
SELECT * FROM products WHERE price = NULL;

-- 正确写法
SELECT * FROM products WHERE price IS NULL;

💡 注释:在 SQL 的三值逻辑中,布尔结果只有三种:TRUEFALSEUNKNOWNNULL 比较的结果是 UNKNOWN,所以无法用于 WHERE 子句的条件判断。


如何正确处理 PostgreSQL NULL 值

使用 IS NULL 和 IS NOT NULL

这是最常用、最安全的方式判断 NULL

-- 查找所有没有填写手机号的用户
SELECT name, phone FROM users WHERE phone IS NULL;

-- 查找所有填写了手机号的用户
SELECT name, phone FROM users WHERE phone IS NOT NULL;

💡 注释:IS NULL 是标准 SQL 的语法,几乎所有数据库都支持,包括 PostgreSQL。记住,它是一个操作符,不是函数。

使用 COALESCE 函数处理默认值

当你希望在 NULL 时提供一个默认值,可以用 COALESCE

-- 如果 phone 是 NULL,就显示 '未提供'
SELECT name, COALESCE(phone, '未提供') AS contact FROM users;

💡 注释:COALESCE 接受多个参数,返回第一个非 NULL 的值。它非常适用于字段值缺失时的优雅降级。

使用 NULLIF 避免无效数据

当你想把某个值转换为 NULL,比如避免除以零,可以用 NULLIF

-- 避免除以零:如果 denominator 是 0,则返回 NULL
SELECT numerator / NULLIF(denominator, 0) AS result FROM calculations;

💡 注释:NULLIF(a, b) 的作用是:如果 a = b,就返回 NULL,否则返回 a。这在数据清洗中特别实用。


实际案例:用户信息表中的 NULL 处理

假设我们有一个用户表 users,结构如下:

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50) NOT NULL,
    email VARCHAR(100),
    phone VARCHAR(20),
    age INT,
    created_at TIMESTAMP DEFAULT NOW()
);

我们插入一些测试数据:

INSERT INTO users (name, email, phone, age) VALUES
('张三', 'zhangsan@example.com', '13800138000', 25),
('李四', NULL, '13900139000', NULL),
('王五', 'wangwu@example.com', NULL, 30),
('赵六', NULL, NULL, 28);

现在我们来查询这些数据:

-- 查看所有记录
SELECT * FROM users;

-- 输出结果:
-- id | name | email | phone | age | created_at
-- 1 | 张三 | zhangsan@example.com | 13800138000 | 25 | ...
-- 2 | 李四 | (null) | 13900139000 | (null) | ...
-- 3 | 王五 | wangwu@example.com | (null) | 30 | ...
-- 4 | 赵六 | (null) | (null) | 28 | ...

案例 1:查找未填写邮箱的用户

SELECT name, email FROM users WHERE email IS NULL;

💡 注释:这条语句会返回“李四”和“赵六”,因为他们没有填写邮箱。

案例 2:为缺失电话的用户补上默认值

SELECT name, COALESCE(phone, '暂无电话') AS contact FROM users;

💡 注释:输出中,“王五”和“赵六”的电话会显示为“暂无电话”,而其他人显示真实号码。

案例 3:统计年龄为空的用户比例

SELECT 
    COUNT(*) AS total_users,
    COUNT(age) AS filled_age,
    COUNT(age) * 100.0 / COUNT(*) AS percentage_filled
FROM users;

💡 注释:COUNT(age) 只统计非 NULL 的值,所以这里可以计算出“年龄填写完整率”。


NULL 值的常见陷阱与最佳实践

陷阱 1:误用 = 判断 NULL

-- ❌ 错误:不会返回任何结果
SELECT * FROM users WHERE age = NULL;

-- ✅ 正确:使用 IS NULL
SELECT * FROM users WHERE age IS NULL;

陷阱 2:在索引中使用 NULL

虽然 PostgreSQL 允许在列上创建索引,但 NULL 值不会被索引包含(除非是部分索引)。

-- 创建索引时,NULL 值不会被存储
CREATE INDEX idx_users_age ON users(age);

💡 建议:如果需要快速查询 NULL 值,可以考虑使用部分索引:

CREATE INDEX idx_users_age_null ON users(age) WHERE age IS NULL;

陷阱 3:聚合函数忽略 NULL

SUMAVGCOUNT 等聚合函数默认忽略 NULL

SELECT AVG(age) FROM users; -- 只计算非 NULL 的 age

💡 注释:COUNT(*) 会统计所有行,而 COUNT(age) 只统计非空的 age。


如何设计数据库以减少 NULL 值的困扰?

1. 合理使用 NOT NULL 约束

在字段确实必须有值时,使用 NOT NULL

CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    name VARCHAR(50) NOT NULL,  -- 必须填写
    email VARCHAR(100) UNIQUE, -- 可以为空,但唯一
    phone VARCHAR(20),
    age INT
);

💡 注释:NOT NULL 能避免意外的 NULL 值,提升数据完整性。

2. 使用默认值代替 NULL

对于“未填写”但需要默认行为的字段,设置默认值。

CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name VARCHAR(100) NOT NULL,
    price DECIMAL(10,2) DEFAULT 0.00,
    status VARCHAR(20) DEFAULT 'active'
);

💡 注释:DEFAULT 保证即使没有插入值,也能有合理默认。


总结:PostgreSQL NULL 值的正确打开方式

NULL 不是“空”,也不是“0”,它是“未知”。它在 PostgreSQL 中扮演着关键角色,但处理不当会引发严重错误。

  • IS NULLIS NOT NULL 判断 NULL
  • COALESCE 提供默认值
  • NULLIF 避免无效计算
  • 聚合函数自动忽略 NULL
  • 合理设计表结构,减少 NULL 的使用

掌握这些技巧,你就能在面对复杂的业务数据时,从容应对各种 NULL 场景。记住:在处理 PostgreSQL NULL 值 时,不是“它是不是空”,而是“它为什么是空”。理解背后的原因,才能写出更健壮的 SQL 代码。

最后,别忘了:NULL 不是错误,它是数据世界中的一种“沉默的语言”。读懂它,你就是数据库的真正主人。