LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

CASE WHEN,90% 的人只用了第一种写法

admin
2026年4月14日 10:45 本文热度 72

你写了很多 SQL,用 CASE WHEN 的方式,大概只有两种:

CASE WHEN col = 'A' THEN '类目A'
     WHEN
 col = 'B' THEN '类目B'
     ELSE
 '其他' END

然后就没了。

如果是这样,你可能低估了 CASE WHEN 功力。


01 UNION ALL 替代:三遍扫描 → 一遍扫描

先看一个场景。

业务方要一张报表,按用户等级分层看数据:

-- 等级分布:高中低三个用户群
SELECT
 '高活跃用户' AS user_group, COUNT(*) AS cnt
FROM
 users WHERE activity_score >= 80
UNION
 ALL
SELECT
 '中活跃用户' AS user_group, COUNT(*) AS cnt
FROM
 users WHERE activity_score BETWEEN 50 AND 79
UNION
 ALL
SELECT
 '低活跃用户' AS user_group, COUNT(*) AS cnt
FROM
 users WHERE activity_score < 50;

三个 UNION ALL,三次全表扫描。假设 users 表 1000 万行,前者扫三遍,后者只扫一遍。

用 CASE WHEN,一遍搞定:

SELECT
    CASE
 WHEN activity_score >= 80   THEN '高活跃用户'
         WHEN
 activity_score >= 50   THEN '中活跃用户'
         ELSE
  '低活跃用户' END AS user_group,
    COUNT
(*) AS cnt
FROM
 users
GROUP
 BY 1;

这就是 CASE WHEN 在 GROUP BY 里的威力——把原本 N 个 UNION ALL 的写法,收成一次扫描加分组。


02 把"不重要"的 N 个值归为"其他"

你做用户地域分析,城市有 50 个,但业务上只关心前 5 个,其他统一归为"其他城市":

SELECT
    CASE
 WHEN city IN ('北京', '上海', '深圳', '广州', '杭州')
         THEN
 city
         ELSE
 '其他城市' END AS city_group,
    COUNT
(*) AS user_cnt
FROM
 users
GROUP
 BY city_group
ORDER
 BY user_cnt DESC;

进阶——用 CASE WHEN 控制 ORDER BY 排序顺序:

SELECT
    CASE
 WHEN city IN ('北京', '上海', '深圳', '广州', '杭州')
         THEN
 city
         ELSE
 '其他城市' END AS city_group,
    COUNT
(*) AS user_cnt
FROM
 users
GROUP
 BY city_group
ORDER
 BY
    CASE
 WHEN city_group = '其他城市' THEN 1 ELSE 0 END,
    user_cnt DESC;

"其他城市"永远排最后。


03 行列转换:把行变成列,做透视表

这是 CASE WHEN 在分析场景里最有价值的用法,没有之一。

看场景:一张订单表,每行是一个用户一个月的消费记录。老板要看每个用户 1 月、2 月、3 月分别花了多少钱,列对齐——这是行转列。

一条 SQL:

SELECT
    user_id,
    SUM
(CASE WHEN month = '2026-01' THEN spend ELSE 0 END) AS jan_spend,
    SUM
(CASE WHEN month = '2026-02' THEN spend ELSE 0 END) AS feb_spend,
    SUM
(CASE WHEN month = '2026-03' THEN spend ELSE 0 END) AS mar_spend,
    SUM
(spend) AS total_spend
FROM
 monthly_spend
WHERE
 month IN ('2026-01', '2026-02', '2026-03')
GROUP
 BY user_id;

结果:

user_id
jan_spend
feb_spend
mar_spend
total_spend
001
500
800
300
1600
002
200
600
0
800

原理:每一列的 SUM 只累加 CASE WHEN 条件为真的那一行,其他行贡献 0——每列对应一个月,列对齐。

进阶:加一个维度(地区),只需 GROUP BY 多写一个字段:

SELECT
    region,
    user_id,
    SUM
(CASE WHEN month = '2026-01' THEN spend ELSE 0 END) AS jan,
    SUM
(CASE WHEN month = '2026-02' THEN spend ELSE 0 END) AS feb,
    SUM
(CASE WHEN month = '2026-03' THEN spend ELSE 0 END) AS mar
FROM
 monthly_spend
WHERE
 month IN ('2026-01', '2026-02', '2026-03')
GROUP
 BY region, user_id
ORDER
 BY region, total_spend DESC;

04 条件聚合:一个 SELECT 同时出多个条件下的指标

这是分析师用得最多、但教程写得最少的一个用法。

场景:同时看"付费用户数"、"免费用户数"、"付费金额"——四个指标,正常写法是四个子查询。

CASE WHEN + 聚合函数,一遍搞定:

SELECT
    region,
    -- 付费用户数

    COUNT
(DISTINCT CASE WHEN is_paid = 1 THEN user_id END) AS paid_user_cnt,
    -- 免费用户数

    COUNT
(DISTINCT CASE WHEN is_paid = 0 THEN user_id END) AS free_user_cnt,
    -- 付费金额

    SUM
(CASE WHEN is_paid = 1 THEN amount ELSE 0 END) AS paid_amount,
    -- 免费引导金额

    SUM
(CASE WHEN is_paid = 0 THEN guide_amount ELSE 0 END) AS free_guide_amount
FROM
 orders
GROUP
 BY region;

注意:CASE WHEN 写在 COUNT(DISTINCT ...) 里面,相当于先过滤再计数。COUNT(col) 忽略 NULL,所以 COUNT 场景下 ELSE NULL 跟不写 ELSE 效果一样。

但 SUM 必须写 ELSE 0——因为 SUM 遇到 NULL 是不累加的,和 ELSE 0 效果一样,但可读性差,容易漏:

-- ❌ 隐患:SUM 忘了写 ELSE,返回结果看起来对但逻辑不清晰
SELECT
 SUM(CASE WHEN is_paid = 1 THEN amount END) AS paid_amount FROM orders;

-- ✅ 标准写法

SELECT
 SUM(CASE WHEN is_paid = 1 THEN amount ELSE 0 END) AS paid_amount FROM orders;

05 多条件嵌套分类:WHEN 里还能再套 WHEN

CASE WHEN 可以嵌套,用来处理两个维度交叉的分类。

场景:给用户打标签,消费频次(高/中/低)× 客单价(高/低),组合成 6 类用户:

SELECT
    user_id,
    CASE

        WHEN
 order_cnt >= 10 AND avg_order_amount >= 500 THEN '高频高价值'
        WHEN
 order_cnt >= 10 AND avg_order_amount < 500  THEN '高频低价值'
        WHEN
 order_cnt >= 3  AND avg_order_amount >= 500 THEN '中频高价值'
        WHEN
 order_cnt >= 3  AND avg_order_amount < 500  THEN '中频低价值'
        WHEN
 avg_order_amount >= 500 THEN '低频高价值'
        ELSE
  '低频低价值'
    END
 AS user_segment
FROM
 user_stats;

条件顺序很重要。 上面把 order_cnt >= 10 的判断放在前面先匹配,如果反过来写,低频高价值用户会被优先匹配为"低频高价值",而实际上如果他同时满足 order_cnt >= 3 应该归入"中频高价值"。


06 综合实战:各城市月度消费趋势表

把前面所有用法串在一起,做一张真实业务里常用的报表:

WITH city_monthly AS (
    SELECT

        CASE

            WHEN
 city IN ('北京', '上海', '深圳', '广州', '杭州')
            THEN
 city
            ELSE
 '其他城市' END AS city_group,
        LEFT
(order_month, 7) AS month,
        SUM
(order_amount) AS monthly_amount
    FROM
 orders
    WHERE
 LEFT(order_month, 7) >= '2026-01'
      AND
 LEFT(order_month, 7) <= '2026-03'
    GROUP
 BY 1, 2
)
SELECT

    city_group,
    SUM
(CASE WHEN month = '2026-01' THEN monthly_amount ELSE 0 END) AS jan_amount,
    SUM
(CASE WHEN month = '2026-02' THEN monthly_amount ELSE 0 END) AS feb_amount,
    SUM
(CASE WHEN month = '2026-03' THEN monthly_amount ELSE 0 END) AS mar_amount,
    SUM
(monthly_amount) AS q1_total,
    ROUND(
        (SUM(CASE WHEN month = '2026-03' THEN monthly_amount ELSE 0 END)
        -
 SUM(CASE WHEN month = '2026-01' THEN monthly_amount ELSE 0 END)) * 100.0
        /
 NULLIF(SUM(CASE WHEN month = '2026-01' THEN monthly_amount ELSE 0 END), 0),
        2

    ) AS q1_growth_pct
FROM
 city_monthly
GROUP
 BY city_group
ORDER
 BY q1_total DESC;

一个 CTE + 一层 SELECT,城市归类、行转列透视、季度环比增长率,全部搞定。


07 CASE WHEN 语法速查

-- 基础语法
CASE

    WHEN
 条件1 THEN 结果1
    WHEN
 条件2 THEN 结果2
    WHEN
 条件3 AND 条件4 THEN 结果3
    ELSE
 默认结果          -- 建议永远写上
END


-- 在 GROUP BY 里

GROUP
 BY CASE WHEN ... END

-- 在聚合函数里

SUM
(CASE WHEN condition THEN col ELSE 0 END)
COUNT
(DISTINCT CASE WHEN condition THEN col END)

-- 嵌套

CASE
 WHEN 条件1 THEN
    CASE
 WHEN 子条件A THEN 'A1' ELSE 'A2' END
WHEN
 条件2 THEN 'B'
ELSE
 'C'
END


阅读原文:原文链接


该文章在 2026/4/14 15:10:49 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2026 ClickSun All Rights Reserved  粤ICP备13012886号-2  粤公网安备44030602007207号