-- 创建测试表
CREATE TABLE IF NOT EXISTS user_profiles (
user_id INT,
user_name STRING,
age INT,
city STRING,
last_login DATE
);
-- 插入测试数据(包含 NULL 值)
INSERT INTO user_profiles VALUES
(1, 'Alice', 28, 'Shanghai', '2024-06-01'),
(2, 'Bob', NULL, 'Beijing', '2024-05-15'),
(3, 'Carol', 35, NULL, '2024-06-02'),
(4, 'David', NULL, NULL, '2024-04-20'),
(5, 'Eve', 22, 'Shanghai', NULL);
基础 NULL 替换
使用
COALESCE
COALESCE
函数按优先级替换 NULL 值,支持多个备选值。
-- 使用 COALESCE 填充缺失的城市信息
SELECT
user_id,
user_name,
COALESCE(city, 'Unknown') as city
FROM user_profiles
ORDER BY user_id;
结果说明:
user_id
user_name
city
1
Alice
Shanghai
2
Bob
Beijing
3
Carol
Unknown
4
David
Unknown
5
Eve
Shanghai
多优先级填充
COALESCE
COALESCE
可以链式使用,按优先级依次尝试:
-- 多优先级填充:优先用城市,其次用 'N/A'
SELECT
user_id,
user_name,
COALESCE(city, user_name, 'N/A') as display_location
FROM user_profiles
ORDER BY user_id;
结果说明:
user_id
user_name
display_location
1
Alice
Shanghai
2
Bob
Beijing
3
Carol
Carol
4
David
David
5
Eve
Shanghai
两值条件替换
当只需要在 NULL 和一个默认值之间切换时,
IFNULL
IFNULL
更简洁。
-- 使用 IFNULL 填充缺失的年龄
SELECT
user_id,
user_name,
IFNULL(age, 0) as age
FROM user_profiles
ORDER BY user_id;
结果说明:
user_id
user_name
age
1
Alice
28
2
Bob
0
3
Carol
35
4
David
0
5
Eve
22
将特定值转为 NULL
使用
NULLIF
NULLIF
将无意义的占位值(如 0、空字符串)转为 NULL:
-- 将年龄为 0 的记录转为 NULL(表示未知)
SELECT
user_id,
user_name,
NULLIF(age, 0) as age
FROM user_profiles
ORDER BY user_id;
前后值填充
在时间序列数据中,常用前一行或后一行的值填充当前缺失值。
-- 使用上一次登录时间填充缺失值
SELECT
user_id,
user_name,
last_login,
LAG(last_login) OVER (ORDER BY user_id) as prev_login,
COALESCE(last_login, LAG(last_login) OVER (ORDER BY user_id)) as filled_login
FROM user_profiles
ORDER BY user_id;
结果说明:
user_id
user_name
last_login
prev_login
filled_login
1
Alice
2024-06-01
NULL
2024-06-01
2
Bob
2024-05-15
2024-06-01
2024-05-15
3
Carol
2024-06-02
2024-05-15
2024-06-02
4
David
2024-04-20
2024-06-02
2024-04-20
5
Eve
NULL
2024-04-20
2024-04-20
⚠️ 注意:数值类型和时间类型的 NULL 在显示时可能分别为
nan
nan
和
NaT
NaT
,但
IS NULL
IS NULL
判断仍然有效。
分组均值填充
对于数值型缺失值,常用同组的平均值或中位数填充。
-- 使用同龄用户的平均年龄填充缺失值(按城市分组)
SELECT
user_id,
user_name,
age,
city,
ROUND(AVG(age) OVER (PARTITION BY city), 1) as city_avg_age,
COALESCE(age, AVG(age) OVER (PARTITION BY city)) as filled_age
FROM user_profiles
ORDER BY user_id;
结果说明:
user_id
user_name
age
city
city_avg_age
filled_age
1
Alice
28
Shanghai
25
28
2
Bob
NULL
Beijing
NULL
NULL
3
Carol
35
NULL
35
35
4
David
NULL
NULL
35
35
5
Eve
22
Shanghai
25
22
💡 提示:
PARTITION BY city
PARTITION BY city
会将 NULL 值分为一组。如果分组内存在非 NULL 值(如 Carol 的 age=35),
AVG
AVG
会忽略 NULL 并返回该组的平均值(35)。若分组内全为 NULL,则
AVG
AVG
返回 NULL,此时
COALESCE
COALESCE
不会填充。可结合全局平均值使用:
COALESCE(age, AVG(age) OVER (PARTITION BY city), AVG(age) OVER ())
COALESCE(age, AVG(age) OVER (PARTITION BY city), AVG(age) OVER ())
。
NULL 值判断
正确处理 NULL 值的逻辑判断,避免常见问题。
-- 正确的 NULL 判断方式
SELECT
user_id,
user_name,
CASE
WHEN age IS NULL THEN 'Unknown'
WHEN age < 18 THEN 'Minor'
WHEN age < 60 THEN 'Adult'
ELSE 'Senior'
END as age_group
FROM user_profiles
ORDER BY user_id;
结果说明:
user_id
user_name
age_group
1
Alice
Adult
2
Bob
Unknown
3
Carol
Adult
4
David
Unknown
5
Eve
Adult
常见问题
-- ❌ 错误:NULL 与任何值比较都返回 NULL(不是 TRUE)
SELECT * FROM user_profiles WHERE age = NULL; -- 返回 0 行
-- ✅ 正确:使用 IS NULL
SELECT * FROM user_profiles WHERE age IS NULL;