概述
CASE 是 PostgreSQL 中最强大的条件表达式之一,它允许你在 SQL 查询中实现类似编程语言中的 if-else 逻辑。CASE 表达式可以根据条件返回不同的值,是处理复杂业务逻辑的重要工具。
基本语法
PostgreSQL 支持两种形式的 CASE 表达式:
1. 简单 CASE(Simple CASE)
类似于 switch-case 语句,用于等值比较。
sql
CASE expression
WHEN value1 THEN result1
WHEN value2 THEN result2
...
ELSE default_result
END
2. 搜索 CASE(Searched CASE)
类似于 if-else if-else 语句,支持任意条件表达式。
sql
CASE
WHEN condition1 THEN result1
WHEN condition2 THEN result2
...
ELSE default_result
END
参数说明
expression:要比较的表达式(仅简单 CASE)WHEN:指定条件或值THEN:条件满足时返回的结果ELSE:所有条件都不满足时的默认结果(可选)END:结束 CASE 表达式
核心特点
1. 短路求值(Short-Circuit Evaluation)
CASE 表达式采用短路求值,一旦某个条件为真,就会立即返回对应结果,不再评估后续条件。
sql
-- 不会报除零错误,因为第一个条件已满足
SELECT CASE
WHEN 1 = 1 THEN 'first'
WHEN 1/0 = 1 THEN 'error' -- 不会执行
END;
2. 必须返回单一值
CASE 表达式必须返回一个值,所有 THEN 子句的结果类型必须兼容。
sql
-- 正确:所有结果都是文本类型
SELECT CASE
WHEN score >= 90 THEN '优秀'
WHEN score >= 60 THEN '及格'
ELSE '不及格'
END AS grade
FROM exams;
-- 错误:类型不兼容
SELECT CASE
WHEN x > 0 THEN 'positive'
ELSE 0 -- 文本和数字类型冲突
END;
3. ELSE 是可选的
如果没有 ELSE 子句且所有条件都不满足,CASE 返回 NULL。
sql
-- 没有 ELSE,不满足条件时返回 NULL
SELECT CASE
WHEN age < 18 THEN '未成年'
END AS status
FROM users;
-- 如果 age >= 18,status 为 NULL
4. 支持嵌套
CASE 表达式可以嵌套使用,实现更复杂的逻辑。
sql
SELECT
name,
CASE
WHEN department = 'IT' THEN
CASE
WHEN salary > 10000 THEN '高级开发'
ELSE '初级开发'
END
ELSE '其他部门'
END AS position
FROM employees;
常见使用场景
1. 数据分类和分组
将连续值转换为分类标签。
sql
-- 年龄分组
SELECT
name,
age,
CASE
WHEN age < 18 THEN '未成年人'
WHEN age BETWEEN 18 AND 35 THEN '青年'
WHEN age BETWEEN 36 AND 60 THEN '中年'
ELSE '老年'
END AS age_group
FROM users;
-- 成绩等级
SELECT
student_name,
score,
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
WHEN score >= 70 THEN 'C'
WHEN score >= 60 THEN 'D'
ELSE 'F'
END AS grade
FROM exam_results;
2. 数据转换和映射
将代码值转换为可读的描述。
sql
-- 状态码转换
SELECT
order_id,
status_code,
CASE status_code
WHEN 0 THEN '待支付'
WHEN 1 THEN '已支付'
WHEN 2 THEN '已发货'
WHEN 3 THEN '已完成'
WHEN 4 THEN '已取消'
ELSE '未知状态'
END AS status_description
FROM orders;
-- 性别转换
SELECT
name,
CASE gender
WHEN 'M' THEN '男'
WHEN 'F' THEN '女'
ELSE '未指定'
END AS gender_cn
FROM customers;
3. 条件聚合
在聚合函数中使用 CASE 进行条件统计。
sql
-- 按类别统计数量
SELECT
department,
COUNT(*) AS total_employees,
COUNT(CASE WHEN salary > 10000 THEN 1 END) AS high_salary_count,
COUNT(CASE WHEN salary <= 10000 THEN 1 END) AS low_salary_count,
AVG(CASE WHEN gender = 'M' THEN salary END) AS male_avg_salary,
AVG(CASE WHEN gender = 'F' THEN salary END) AS female_avg_salary
FROM employees
GROUP BY department;
-- 透视表(Pivot)
SELECT
EXTRACT(YEAR FROM order_date) AS year,
SUM(CASE WHEN EXTRACT(MONTH FROM order_date) = 1 THEN amount ELSE 0 END) AS jan_sales,
SUM(CASE WHEN EXTRACT(MONTH FROM order_date) = 2 THEN amount ELSE 0 END) AS feb_sales,
SUM(CASE WHEN EXTRACT(MONTH FROM order_date) = 3 THEN amount ELSE 0 END) AS mar_sales
FROM orders
GROUP BY EXTRACT(YEAR FROM order_date);
4. 条件排序
根据业务逻辑动态决定排序规则。
sql
-- 优先显示 VIP 客户,然后按消费金额排序
SELECT * FROM customers
ORDER BY
CASE
WHEN vip_level = 'gold' THEN 1
WHEN vip_level = 'silver' THEN 2
ELSE 3
END,
total_spent DESC;
-- 多条件动态排序
SELECT * FROM products
ORDER BY
CASE
WHEN :sort_by = 'price' THEN price
WHEN :sort_by = 'name' THEN NULL -- 需要单独处理
END ASC,
CASE
WHEN :sort_by = 'name' THEN product_name
END ASC;
5. 数据验证和清洗
在查询中进行数据验证和修正。
sql
-- 修正异常数据
SELECT
product_id,
CASE
WHEN price < 0 THEN 0
WHEN price IS NULL THEN 0
ELSE price
END AS valid_price,
CASE
WHEN stock < 0 THEN 0
ELSE stock
END AS valid_stock
FROM products;
-- 标记无效记录
SELECT
user_id,
email,
CASE
WHEN email IS NULL OR email = '' THEN '缺少邮箱'
WHEN email NOT LIKE '%@%' THEN '邮箱格式错误'
ELSE '有效'
END AS email_status
FROM users;
6. 条件计算
根据不同条件执行不同的计算逻辑。
sql
-- 阶梯折扣计算
SELECT
order_id,
total_amount,
CASE
WHEN total_amount >= 1000 THEN total_amount * 0.8 -- 8折
WHEN total_amount >= 500 THEN total_amount * 0.9 -- 9折
WHEN total_amount >= 200 THEN total_amount * 0.95 -- 95折
ELSE total_amount -- 无折扣
END AS final_amount
FROM orders;
-- 工作日判断
SELECT
order_date,
CASE
WHEN EXTRACT(DOW FROM order_date) IN (0, 6) THEN '周末'
ELSE '工作日'
END AS day_type,
CASE
WHEN EXTRACT(DOW FROM order_date) IN (0, 6) THEN total_amount * 1.1
ELSE total_amount
END AS adjusted_amount
FROM orders;
7. UPDATE 中的条件更新
根据条件批量更新不同值。
sql
-- 根据现有值条件更新
UPDATE employees
SET salary = CASE
WHEN performance_score >= 90 THEN salary * 1.2 -- 优秀涨薪20%
WHEN performance_score >= 70 THEN salary * 1.1 -- 良好涨薪10%
ELSE salary * 1.05 -- 其他涨薪5%
END,
updated_at = NOW()
WHERE department = 'IT';
-- 空值填充
UPDATE users
SET nickname = CASE
WHEN nickname IS NULL OR nickname = '' THEN username
ELSE nickname
END;
8. INSERT 中的条件插入
sql
INSERT INTO user_profiles (user_id, level, badge)
SELECT
user_id,
CASE
WHEN total_points >= 10000 THEN '钻石'
WHEN total_points >= 5000 THEN '黄金'
WHEN total_points >= 1000 THEN '白银'
ELSE '青铜'
END AS level,
CASE
WHEN login_days >= 365 THEN '年度活跃'
WHEN login_days >= 30 THEN '月度活跃'
ELSE '新用户'
END AS badge
FROM user_stats;
高级用法
1. 与聚合函数结合
sql
-- 条件计数和求和
SELECT
department,
COUNT(*) AS total,
SUM(CASE WHEN gender = 'M' THEN 1 ELSE 0 END) AS male_count,
SUM(CASE WHEN gender = 'F' THEN 1 ELSE 0 END) AS female_count,
ROUND(
AVG(CASE WHEN gender = 'M' THEN salary END), 2
) AS male_avg_salary,
ROUND(
AVG(CASE WHEN gender = 'F' THEN salary END), 2
) AS female_avg_salary
FROM employees
GROUP BY department;
2. 与窗口函数结合
sql
-- 按等级分配排名
SELECT
name,
score,
CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
ELSE 'C'
END AS grade,
RANK() OVER (
PARTITION BY CASE
WHEN score >= 90 THEN 'A'
WHEN score >= 80 THEN 'B'
ELSE 'C'
END
ORDER BY score DESC
) AS grade_rank
FROM students;
3. 与 COALESCE 结合
sql
-- 处理 NULL 值和条件逻辑
SELECT
name,
COALESCE(
CASE
WHEN discount_rate > 0 THEN price * (1 - discount_rate)
END,
price
) AS final_price
FROM products;
4. 与 NULLIF 结合
sql
-- 避免除零错误并处理特殊情况
SELECT
product_id,
revenue,
units_sold,
CASE
WHEN units_sold = 0 THEN NULL
ELSE revenue / NULLIF(units_sold, 0)
END AS avg_price_per_unit
FROM sales;
5. 在 HAVING 子句中使用
sql
-- 筛选特定条件的分组
SELECT
department,
AVG(salary) AS avg_salary
FROM employees
GROUP BY department
HAVING
MAX(CASE WHEN hire_date < '2020-01-01' THEN 1 ELSE 0 END) = 1
AND AVG(salary) > 8000;
6. 动态列选择
sql
-- 根据条件选择显示不同列
SELECT
product_id,
product_name,
CASE
WHEN show_original_price = true THEN original_price
ELSE sale_price
END AS display_price
FROM products;
性能优化建议
1. 条件顺序优化
将最可能匹配的条件放在前面,利用短路特性提高性能。
sql
-- 优化前
SELECT CASE
WHEN rare_condition THEN 'rare' -- 很少命中
WHEN common_condition THEN 'common' -- 经常命中
END FROM table;
-- 优化后
SELECT CASE
WHEN common_condition THEN 'common' -- 经常命中,先检查
WHEN rare_condition THEN 'rare' -- 很少命中
END FROM table;
2. 避免在 WHERE 中过度使用
在 WHERE 子句中大量使用 CASE 可能导致索引失效。
sql
-- 可能无法使用索引
SELECT * FROM orders
WHERE CASE
WHEN status = 'active' THEN 1
ELSE 0
END = 1;
-- 更好的写法
SELECT * FROM orders
WHERE status = 'active';
3. 简化复杂 CASE
过于复杂的 CASE 可以考虑拆分为多个查询或使用临时表。
sql
-- 过于复杂,难以维护
SELECT CASE
WHEN condition1 AND condition2 AND condition3 THEN result1
WHEN condition4 OR condition5 THEN result2
...
END FROM table;
-- 考虑使用 CTE 或临时表简化
WITH categorized AS (
SELECT *,
condition1 AND condition2 AND condition3 AS is_category1,
condition4 OR condition5 AS is_category2
FROM table
)
SELECT
CASE
WHEN is_category1 THEN result1
WHEN is_category2 THEN result2
END AS result
FROM categorized;
4. 使用简单 CASE 替代搜索 CASE
当只需要等值比较时,使用简单 CASE 更清晰且性能略优。
sql
-- 搜索 CASE(通用但冗长)
SELECT CASE
WHEN status = 1 THEN 'active'
WHEN status = 2 THEN 'inactive'
WHEN status = 3 THEN 'pending'
END FROM table;
-- 简单 CASE(简洁高效)
SELECT CASE status
WHEN 1 THEN 'active'
WHEN 2 THEN 'inactive'
WHEN 3 THEN 'pending'
END FROM table;
与其他方法的对比
CASE vs COALESCE
sql
-- COALESCE:仅处理 NULL 值(简洁)
SELECT COALESCE(nickname, username, 'anonymous') FROM users;
-- CASE:处理复杂条件(灵活)
SELECT CASE
WHEN nickname IS NOT NULL AND nickname != '' THEN nickname
WHEN username IS NOT NULL THEN username
ELSE 'anonymous'
END FROM users;
选择建议:
- 仅处理 NULL → COALESCE
- 复杂条件逻辑 → CASE
CASE vs DECODE
PostgreSQL 不支持 Oracle 的 DECODE 函数,CASE 是其标准替代品。
sql
-- Oracle DECODE(PostgreSQL 不支持)
DECODE(status, 1, 'active', 2, 'inactive', 'unknown')
-- PostgreSQL CASE(推荐)
CASE status
WHEN 1 THEN 'active'
WHEN 2 THEN 'inactive'
ELSE 'unknown'
END
CASE vs IF/ELSE
PostgreSQL 不支持 SQL 中的 IF/ELSE(仅在 PL/pgSQL 中支持),CASE 是标准 SQL 的条件表达式。
sql
-- PL/pgSQL 中的 IF/ELSE(存储过程)
IF condition THEN
result := 'value1';
ELSE
result := 'value2';
END IF;
-- 标准 SQL 中的 CASE(查询中)
SELECT CASE
WHEN condition THEN 'value1'
ELSE 'value2'
END AS result;
实际应用示例
示例 1:电商订单分析报表
sql
SELECT
EXTRACT(YEAR FROM order_date) AS year,
EXTRACT(MONTH FROM order_date) AS month,
COUNT(*) AS order_count,
SUM(total_amount) AS total_revenue,
AVG(total_amount) AS avg_order_value,
-- 订单状态分布
COUNT(CASE WHEN status = 'completed' THEN 1 END) AS completed_orders,
COUNT(CASE WHEN status = 'cancelled' THEN 1 END) AS cancelled_orders,
-- 支付方式分布
COUNT(CASE WHEN payment_method = 'alipay' THEN 1 END) AS alipay_count,
COUNT(CASE WHEN payment_method = 'wechat' THEN 1 END) AS wechat_count,
-- 客户类型分布
COUNT(CASE WHEN customer_type = 'vip' THEN 1 END) AS vip_orders,
COUNT(CASE WHEN customer_type = 'regular' THEN 1 END) AS regular_orders,
-- 平均客单价分层
COUNT(CASE WHEN total_amount >= 1000 THEN 1 END) AS high_value_orders,
COUNT(CASE WHEN total_amount BETWEEN 500 AND 999 THEN 1 END) AS medium_value_orders,
COUNT(CASE WHEN total_amount < 500 THEN 1 END) AS low_value_orders
FROM orders
WHERE order_date >= '2024-01-01'
GROUP BY EXTRACT(YEAR FROM order_date), EXTRACT(MONTH FROM order_date)
ORDER BY year, month;
示例 2:员工绩效评估系统
sql
SELECT
e.employee_id,
e.name,
e.department,
-- 综合评分
(e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) AS total_score,
-- 绩效等级
CASE
WHEN (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 90 THEN 'S'
WHEN (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 80 THEN 'A'
WHEN (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 70 THEN 'B'
WHEN (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 60 THEN 'C'
ELSE 'D'
END AS performance_grade,
-- 奖金计算
CASE
WHEN (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 90 THEN e.base_salary * 0.3
WHEN (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 80 THEN e.base_salary * 0.2
WHEN (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 70 THEN e.base_salary * 0.1
ELSE 0
END AS bonus_amount,
-- 晋升资格
CASE
WHEN e.years_of_service >= 3
AND (e.performance_score * 0.6 + e.attendance_score * 0.3 + e.teamwork_score * 0.1) >= 85
THEN '符合资格'
ELSE '暂不符合'
END AS promotion_eligible
FROM employees e
WHERE e.status = 'active';
示例 3:学生成绩综合分析
sql
SELECT
s.student_id,
s.name,
s.class,
-- 各科成绩
g.math_score,
g.english_score,
g.science_score,
-- 总分
(g.math_score + g.english_score + g.science_score) AS total_score,
-- 平均分
ROUND((g.math_score + g.english_score + g.science_score) / 3.0, 2) AS avg_score,
-- 综合等级
CASE
WHEN (g.math_score + g.english_score + g.science_score) / 3.0 >= 90 THEN '优秀'
WHEN (g.math_score + g.english_score + g.science_score) / 3.0 >= 80 THEN '良好'
WHEN (g.math_score + g.english_score + g.science_score) / 3.0 >= 70 THEN '中等'
WHEN (g.math_score + g.english_score + g.science_score) / 3.0 >= 60 THEN '及格'
ELSE '不及格'
END AS overall_grade,
-- 优势科目
CASE
WHEN g.math_score >= g.english_score AND g.math_score >= g.science_score THEN '数学'
WHEN g.english_score >= g.math_score AND g.english_score >= g.science_score THEN '英语'
ELSE '科学'
END AS best_subject,
-- 是否需要补考
CASE
WHEN g.math_score < 60 OR g.english_score < 60 OR g.science_score < 60 THEN '是'
ELSE '否'
END AS needs_retake
FROM students s
JOIN grades g ON s.student_id = g.student_id
WHERE g.exam_date = '2024-06-01';
示例 4:库存预警系统
sql
SELECT
p.product_id,
p.product_name,
p.category,
i.current_stock,
i.reorder_level,
-- 库存状态
CASE
WHEN i.current_stock = 0 THEN '缺货'
WHEN i.current_stock <= i.reorder_level * 0.5 THEN '严重不足'
WHEN i.current_stock <= i.reorder_level THEN '需要补货'
WHEN i.current_stock <= i.reorder_level * 2 THEN '库存偏低'
ELSE '库存充足'
END AS stock_status,
-- 建议操作
CASE
WHEN i.current_stock = 0 THEN '紧急采购'
WHEN i.current_stock <= i.reorder_level * 0.5 THEN '立即补货'
WHEN i.current_stock <= i.reorder_level THEN '计划补货'
ELSE '无需操作'
END AS recommended_action,
-- 建议补货数量
CASE
WHEN i.current_stock <= i.reorder_level THEN
GREATEST(i.reorder_level * 3 - i.current_stock, 0)
ELSE 0
END AS suggested_order_quantity
FROM products p
JOIN inventory i ON p.product_id = i.product_id
ORDER BY
CASE
WHEN i.current_stock = 0 THEN 1
WHEN i.current_stock <= i.reorder_level * 0.5 THEN 2
WHEN i.current_stock <= i.reorder_level THEN 3
ELSE 4
END;
示例 5:用户行为分析
sql
SELECT
u.user_id,
u.username,
u.register_date,
-- 用户活跃度
CASE
WHEN last_login_date >= CURRENT_DATE - INTERVAL '1 day' THEN '今日活跃'
WHEN last_login_date >= CURRENT_DATE - INTERVAL '7 days' THEN '本周活跃'
WHEN last_login_date >= CURRENT_DATE - INTERVAL '30 days' THEN '本月活跃'
WHEN last_login_date >= CURRENT_DATE - INTERVAL '90 days' THEN '近期活跃'
ELSE '流失用户'
END AS activity_status,
-- 用户价值等级
CASE
WHEN total_spent >= 10000 THEN '高价值用户'
WHEN total_spent >= 5000 THEN '中高价值用户'
WHEN total_spent >= 1000 THEN '中等价值用户'
WHEN total_spent > 0 THEN '低价值用户'
ELSE '未消费用户'
END AS value_tier,
-- 用户生命周期阶段
CASE
WHEN CURRENT_DATE - register_date <= INTERVAL '7 days' THEN '新用户'
WHEN CURRENT_DATE - register_date <= INTERVAL '90 days' THEN '成长期用户'
WHEN CURRENT_DATE - register_date <= INTERVAL '365 days' THEN '成熟期用户'
ELSE '老用户'
END AS lifecycle_stage,
-- 推荐营销策略
CASE
WHEN last_login_date < CURRENT_DATE - INTERVAL '30 days' AND total_spent > 0 THEN '召回营销'
WHEN total_spent = 0 AND CURRENT_DATE - register_date > INTERVAL '7 days' THEN '激活营销'
WHEN total_spent >= 5000 THEN 'VIP维护'
ELSE '常规运营'
END AS marketing_strategy
FROM users u
ORDER BY
CASE
WHEN last_login_date >= CURRENT_DATE - INTERVAL '1 day' THEN 1
WHEN last_login_date >= CURRENT_DATE - INTERVAL '7 days' THEN 2
ELSE 3
END;
注意事项和最佳实践
✅ 推荐做法
-
始终包含 ELSE 子句:明确处理未匹配的情况
sqlCASE WHEN condition THEN result ELSE NULL -- 显式说明 END -
保持条件互斥:避免条件重叠导致逻辑混乱
sqlCASE WHEN score >= 90 THEN 'A' WHEN score >= 80 THEN 'B' -- 隐含 score < 90 WHEN score >= 70 THEN 'C' -- 隐含 score < 80 END -
使用有意义的注释:说明复杂 CASE 的业务逻辑
sqlCASE -- VIP 客户享受更高折扣 WHEN customer_type = 'vip' THEN price * 0.7 -- 普通会员标准折扣 ELSE price * 0.9 END -
格式化代码:每个 WHEN 一行,提高可读性
sqlCASE WHEN condition1 THEN result1 WHEN condition2 THEN result2 ELSE default_result END -
提取重复逻辑:使用 CTE 或子查询避免重复 CASE
sqlWITH scored AS ( SELECT *, (math + english + science) / 3.0 AS avg_score FROM grades ) SELECT *, CASE WHEN avg_score >= 90 THEN 'A' ELSE 'B' END AS grade FROM scored;
❌ 避免的做法
- 不要过度嵌套:超过 3 层嵌套应考虑重构
- 避免过长的 CASE:超过 10 个 WHEN 考虑使用查找表
- 不要在 JOIN 条件中滥用:可能导致性能问题
- 避免类型不一致:确保所有 THEN 返回相同类型
- 不要忽略 NULL 处理:明确 NULL 的行为
常见陷阱
sql
-- 陷阱 1:忘记 ELSE,意外返回 NULL
SELECT CASE
WHEN status = 1 THEN 'active'
-- 缺少 ELSE,status != 1 时返回 NULL
END FROM table;
-- 陷阱 2:条件顺序错误
SELECT CASE
WHEN score >= 60 THEN '及格' -- 先检查,会捕获所有 >= 60
WHEN score >= 90 THEN '优秀' -- 永远不会执行!
END FROM exams;
-- 正确:从严格到宽松
SELECT CASE
WHEN score >= 90 THEN '优秀'
WHEN score >= 60 THEN '及格'
END FROM exams;
-- 陷阱 3:NULL 比较
SELECT CASE
WHEN value = NULL THEN 'is null' -- 永远为假!
ELSE 'not null'
END FROM table;
-- 正确:使用 IS NULL
SELECT CASE
WHEN value IS NULL THEN 'is null'
ELSE 'not null'
END FROM table;
-- 陷阱 4:浮点数精度问题
SELECT CASE
WHEN price = 19.99 THEN 'match' -- 可能不匹配
END FROM products;
-- 更好:使用范围比较
SELECT CASE
WHEN price BETWEEN 19.98 AND 20.00 THEN 'match'
END FROM products;
常见问题 FAQ
Q1: CASE 和 COALESCE 有什么区别?
A: COALESCE 只处理 NULL 值,返回第一个非 NULL 值;CASE 可以处理任意条件逻辑。COALESCE 是 CASE 的特例。
Q2: CASE 的性能如何?
A: CASE 性能良好,特别是简单 CASE。但在 WHERE 子句中大量使用可能影响索引使用。建议:
- 保持条件简洁
- 合理排序条件
- 避免在索引列上使用复杂 CASE
Q3: CASE 可以用于 ORDER BY 吗?
A: 可以,非常有用:
sql
SELECT * FROM products
ORDER BY
CASE category
WHEN 'electronics' THEN 1
WHEN 'books' THEN 2
ELSE 3
END;
Q4: CASE 的最大 WHEN 数量有限制吗?
A: PostgreSQL 没有硬性限制,但建议不超过 20-30 个 WHEN。过多时应考虑使用查找表。
Q5: 如何在 CASE 中处理 NULL?
A: 使用 IS NULL 或 IS NOT NULL:
sql
CASE
WHEN value IS NULL THEN 'null'
WHEN value IS NOT NULL THEN 'not null'
END
总结
CASE 表达式是 PostgreSQL 中最灵活、最强大的条件处理工具,具有以下优势:
- ✨ 灵活性:支持任意条件表达式,处理复杂业务逻辑
- 🚀 性能:短路求值,条件顺序优化可提升性能
- 🔧 通用性:可用于 SELECT、WHERE、ORDER BY、HAVING、UPDATE 等所有子句
- 📦 标准化:符合 SQL 标准,具有良好的可移植性
适用场景:
- 数据分类和分组
- 代码值转换
- 条件聚合和统计
- 动态排序
- 数据验证和清洗
- 条件计算和更新
不适用场景:
- 简单的 NULL 处理(用 COALESCE)
- 超复杂逻辑(考虑应用层处理)
- 频繁的等值映射(考虑查找表)
合理使用 CASE 表达式可以让 SQL 查询更加灵活、强大和易于维护。记住关键原则:保持简洁、明确 ELSE、注意顺序、处理 NULL。