PostgreSQL NULL值
概述
NULL表示"未知"或"无值",它不等于空字符串或零。在PostgreSQL中正确处理NULL值对于数据完整性和查询准确性非常重要。
NULL的特性
基本特性
- NULL不等于任何值,包括NULL本身
- NULL与任何值的运算结果都是NULL
- NULL在布尔运算中表示"未知"
sql
-- NULL的比较
SELECT NULL = NULL; -- 结果: NULL(不是TRUE)
SELECT NULL <> NULL; -- 结果: NULL
SELECT NULL = 0; -- 结果: NULL
SELECT NULL = ''; -- 结果: NULL检测NULL值
IS NULL和IS NOT NULL
sql
-- 查找空值
SELECT * FROM users WHERE email IS NULL;
-- 查找非空值
SELECT * FROM users WHERE email IS NOT NULL;
-- 错误写法(永远不会返回结果)
SELECT * FROM users WHERE email = NULL; -- 不要这样写!NULL与运算
算术运算
sql
SELECT 10 + NULL; -- 结果: NULL
SELECT 10 * NULL; -- 结果: NULL
SELECT 10 / NULL; -- 结果: NULL
SELECT NULL + NULL; -- 结果: NULL字符串连接
sql
SELECT 'Hello' || NULL; -- 结果: NULL
SELECT CONCAT('Hello', NULL, 'World'); -- 结果: 'HelloWorld'(CONCAT忽略NULL)布尔运算
sql
SELECT TRUE AND NULL; -- 结果: NULL
SELECT FALSE AND NULL; -- 结果: FALSE
SELECT TRUE OR NULL; -- 结果: TRUE
SELECT FALSE OR NULL; -- 结果: NULL
SELECT NOT NULL; -- 结果: NULL处理NULL的函数
COALESCE函数
返回第一个非NULL值:
sql
-- 基本用法
SELECT COALESCE(NULL, 'default'); -- 结果: 'default'
SELECT COALESCE(NULL, NULL, 'third'); -- 结果: 'third'
SELECT COALESCE('first', NULL, 'third'); -- 结果: 'first'
-- 实际应用
SELECT
username,
COALESCE(nickname, username) as display_name
FROM users;
-- 处理可能为NULL的计算
SELECT
product_name,
COALESCE(discount_price, original_price) as actual_price
FROM products;NULLIF函数
如果两个值相等则返回NULL:
sql
-- 基本用法
SELECT NULLIF(10, 10); -- 结果: NULL
SELECT NULLIF(10, 20); -- 结果: 10
-- 避免除零错误
SELECT 100 / NULLIF(divisor, 0) FROM calculations;
-- 将空字符串转为NULL
SELECT NULLIF(email, '') FROM users;NVL函数(通过COALESCE实现)
sql
-- PostgreSQL没有NVL,使用COALESCE替代
SELECT COALESCE(commission, 0) FROM employees;NULL与聚合函数
聚合函数忽略NULL
sql
-- COUNT(*)计算所有行,COUNT(column)忽略NULL
SELECT COUNT(*) FROM users; -- 所有行
SELECT COUNT(email) FROM users; -- email不为NULL的行
-- SUM、AVG等忽略NULL值
SELECT AVG(salary) FROM employees; -- 只计算非NULL值的平均
-- 示例数据
-- salary: 100, 200, NULL, 300
SELECT AVG(salary); -- 结果: 200(不是150)包含NULL的聚合
sql
-- 如果需要将NULL视为0
SELECT AVG(COALESCE(salary, 0)) FROM employees;
-- 统计NULL值数量
SELECT COUNT(*) - COUNT(column_name) as null_count FROM table_name;NULL与排序
默认排序行为
sql
-- ASC时NULL排在最后
SELECT * FROM products ORDER BY price ASC;
-- DESC时NULL排在最前
SELECT * FROM products ORDER BY price DESC;控制NULL排序位置
sql
-- NULL排在最前
SELECT * FROM products ORDER BY price NULLS FIRST;
-- NULL排在最后
SELECT * FROM products ORDER BY price DESC NULLS LAST;NULL与DISTINCT
sql
-- DISTINCT将所有NULL视为相等
SELECT DISTINCT category FROM products;
-- 多个NULL只返回一个NULLNULL与索引
B-tree索引
sql
-- 默认B-tree索引不包含NULL值的部分查询
CREATE INDEX idx_email ON users(email);
-- 查询NULL时可能不使用索引
SELECT * FROM users WHERE email IS NULL;部分索引优化
sql
-- 创建只包含非NULL值的索引
CREATE INDEX idx_email_not_null ON users(email)
WHERE email IS NOT NULL;
-- 创建只包含NULL值的索引
CREATE INDEX idx_email_null ON users((email IS NULL))
WHERE email IS NULL;NULL与约束
NOT NULL约束
sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(50) NOT NULL, -- 不允许NULL
email VARCHAR(100) -- 允许NULL
);UNIQUE约束与NULL
sql
-- UNIQUE允许多个NULL值
CREATE TABLE test (
id SERIAL PRIMARY KEY,
code VARCHAR(10) UNIQUE
);
INSERT INTO test (code) VALUES (NULL);
INSERT INTO test (code) VALUES (NULL); -- 成功!允许多个NULLCHECK约束与NULL
sql
-- CHECK约束中NULL被视为通过
CREATE TABLE products (
id SERIAL PRIMARY KEY,
price DECIMAL CHECK (price > 0)
);
INSERT INTO products (price) VALUES (NULL); -- 成功!实际应用示例
处理可选字段
sql
SELECT
first_name,
last_name,
COALESCE(middle_name, '') as middle_name,
COALESCE(phone, 'N/A') as phone
FROM customers;条件替换
sql
SELECT
product_name,
CASE
WHEN stock IS NULL THEN 'Unknown'
WHEN stock = 0 THEN 'Out of Stock'
ELSE 'In Stock'
END as availability
FROM products;安全的数值计算
sql
SELECT
order_id,
quantity * COALESCE(unit_price, 0) as line_total
FROM order_items;最佳实践
- 使用IS NULL:永远不要用
= NULL比较 - 善用COALESCE:提供默认值避免NULL传播
- 注意聚合:了解聚合函数如何处理NULL
- 文档化:记录哪些列允许NULL及其业务含义
- 默认值:考虑使用DEFAULT而不是允许NULL