4. CASE WHEN 条件逻辑:标记异常、分类统计与条件计数
CASE WHEN 是 SQL 中实现条件分支的核心语法,在数据质量探查中,它能够帮助我们根据字段值动态生成新标签、对异常数据进行标记、完成复杂的分类汇总,以及实现条件计数。掌握 CASE WHEN,是数据探查从“看数据”走向“判数据”的关键一步。
4.1 语法结构:两种写法
| 写法 | 语法 | 适用场景 |
|---|---|---|
| 简单 CASE | CASE 字段 WHEN 值1 THEN 结果1 WHEN 值2 THEN 结果2 ELSE 默认 END |
字段值与固定枚举值一一匹配(如性别、状态码) |
| 搜索 CASE | CASE WHEN 条件1 THEN 结果1 WHEN 条件2 THEN 结果2 ELSE 默认 END |
基于范围、多字段组合、复杂布尔表达式判断(如年龄区间、异常规则) |
探查实践建议: 数据质量探查中优先使用搜索 CASE,因为它能灵活处理 NULL、边界值、多条件组合,是标记异常值的主要工具。
4.2 数据探查三大应用场景
4.2.1 标记异常值
通过 CASE WHEN 将不符合业务规则的数据打上“异常”标签,便于后续过滤或统计异常率。
-- 标记订单金额异常:负值或超过 100 万
SELECT
order_id,
amount,
CASE
WHEN amount IS NULL THEN '空值'
WHEN amount < 0 THEN '负值异常'
WHEN amount > 1000000 THEN '超限异常'
ELSE '正常'
END AS amount_status
FROM orders;
4.2.2 分类统计
将连续值或离散值映射为业务分类,配合 GROUP BY 实现多维度汇总。
-- 按年龄分组统计用户分布
SELECT
CASE
WHEN age < 18 THEN '未成年'
WHEN age BETWEEN 18 AND 30 THEN '青年'
WHEN age BETWEEN 31 AND 50 THEN '中年'
WHEN age > 50 THEN '老年'
ELSE '未知'
END AS age_group,
COUNT(*) AS user_count
FROM users
GROUP BY age_group;
4.2.3 条件计数
在 COUNT 或 SUM 中嵌入 CASE WHEN,实现单行多条件计数,避免多次扫描表。
-- 一次查询统计各类异常数量
SELECT
COUNT(*) AS total_records,
SUM(CASE WHEN amount IS NULL THEN 1 ELSE 0 END) AS null_count,
SUM(CASE WHEN amount < 0 THEN 1 ELSE 0 END) AS negative_count,
SUM(CASE WHEN amount > 1000000 THEN 1 ELSE 0 END) AS over_limit_count
FROM orders;
效率提示: 条件计数比写多个 COUNT(CASE...) 子查询更高效,尤其在大表探查时,一次扫描即可完成多个质量指标计算。
4.3 CASE WHEN 执行流程
注意: CASE WHEN 按顺序评估条件,一旦某个 WHEN 条件为 TRUE,立即返回对应结果,不再评估后续条件。因此,应将最严格或最具体的条件放在前面。
4.4 常见陷阱与避坑指南
| 陷阱 | 错误示例 | 正确做法 |
|---|---|---|
| NULL 处理遗漏 | CASE WHEN amount > 0 THEN '正数' ELSE '非正' END(NULL 被归入 ELSE) |
先判断 WHEN amount IS NULL THEN '空值' |
| 条件顺序错误 | WHEN age > 18 THEN '成年' WHEN age > 60 THEN '老年'(老年永远不触发) |
将最具体条件放前:WHEN age > 60 THEN '老年' WHEN age > 18 THEN '成年' |
| 数据类型不一致 | CASE WHEN flag=1 THEN '是' ELSE 0 END(字符串与数字混用) |
所有 THEN/ELSE 返回同一数据类型 |
| 忘记 END | CASE WHEN ... THEN ... ELSE ... 缺少 END |
每个 CASE 必须配对 END |
4.5 实战案例:客户数据质量探查
-- 综合探查:标记异常 + 分类统计 + 条件计数
SELECT
-- 条件计数:各类异常数量
COUNT(*) AS total_customers,
SUM(CASE WHEN name IS NULL OR TRIM(name) = '' THEN 1 ELSE 0 END) AS name_issue_count,
SUM(CASE WHEN phone NOT REGEXP '^1[3-9]\\d{9}$' THEN 1 ELSE 0 END) AS phone_issue_count,
SUM(CASE WHEN email NOT LIKE '%@%.%' THEN 1 ELSE 0 END) AS email_issue_count,
-- 分类统计:按数据质量等级分组
CASE
WHEN name IS NULL OR phone IS NULL OR email IS NULL THEN '严重缺失'
WHEN TRIM(name) = '' OR phone NOT REGEXP '^1[3-9]\\d{9}$' THEN '格式异常'
ELSE '质量合格'
END AS quality_level,
COUNT(*) AS level_count
FROM customers
GROUP BY quality_level;
探查要点: 一次查询同时输出总体异常计数和按质量等级的分组统计,既能看到全局异常率,又能定位到具体哪些记录属于哪个等级,是数据质量探查的典型输出模式。