用CASE WHEN在聚合函数内做条件分支是实现带权重/优先级聚合最可控通用的方式;GROUP BY不保留顺序,ORDER BY在聚合后生效,无法影响聚合逻辑,必须用CASE显式映射数值参与计算。
直接结论:用在聚合函数内部做条件分支,是实现带权重/优先级聚合最可控、最通用的方式;别指望本身能“自动排序优先级”。
为什么不能只靠 GROUP BY 或 ORDER BY 实现优先级聚合
很多人误以为给分组加个
就能让
或
“优先取高优先级值”,但这是错的。
只负责切分数据块,
在聚合之后才生效(除非嵌套子查询),对聚合逻辑本身无影响。
阶段不保留行顺序,
取的是值最大,不是“优先级最高”的那条记录
想让某类记录在聚合中“占更大比重”,必须显式用
把它映射成数值参与计算
如果只是想“按优先级选一条代表值”,得配合窗口函数(如
),而不是纯聚合
CASE WHEN + SUM 实现加权求和(最常用场景)
典型需求:不同状态订单贡献不同权重——已支付订单计 1.0,待审核计 0.5,已取消计 0 —— 最终算“等效订单量”。
每个
分支返回数值,
对这些数值累加
注意
必须写,否则
会被
忽略,导致结果偏小
权重可以是任意数值,支持小数、负数、甚至动态表达式(如
)
CASE WHEN + MAX/MIN 实现“优先取值”逻辑
这不是真·聚合,而是用聚合函数“借壳”实现条件选取。例如:每类产品只取“最高优先级渠道”的价格,优先级定义为
。
这里
起的是“兜底”作用:只要某优先级分支命中,就返回对应
;多个命中时取数值最大者(非优先级最高者)→ 所以要确保高优先级分支排在前面,且用
避免干扰
更稳妥的做法是用
先排序再过滤,但若仅需单值且逻辑简单,
更轻量
别用
代替加权求和——它只统计命中次数,不体现权重差异
容易被忽略的坑:NULL 处理与执行顺序
所有带
的聚合都绕不开两个硬约束:
中没覆盖全分支且没写
→ 返回
→
忽略,
计算时自动剔除该行,但
仍会计数(因
统计行,
才跳过
)
在
和
之前执行,所以不能在
里引用
别名;如需先筛再加权,必须把
写进
子句或用子查询
聚合字段上建索引对
加权无加速效果,真正影响性能的是
条件列和
字段的索引
优先级不是语法特性,是业务逻辑。写
时多花十秒想清楚“这个分支漏了会怎样”,比调半天结果不对更省时间。
CASE WHENGROUP BYORDER BY priority DESCSUM()MAX()GROUP BYORDER BYGROUP BYMAX()CASEROW_NUMBER() OVER (PARTITION BY ... ORDER BY priority DESC)
SELECT
SUM(CASE
WHEN status = 'paid' THEN 1.0
WHEN status = 'pending' THEN 0.5
ELSE 0
END) AS weighted_order_count
FROM orders;
CASESUM()ELSE 0NULLSUM()amount * 0.1channel_priority = {'official': 3, 'partner': 2, 'reseller': 1}
SELECT
product_id,
MAX(CASE
WHEN channel = 'official' THEN price
WHEN channel = 'partner' THEN price
WHEN channel = 'reseller' THEN price
ELSE NULL
END) AS effective_price
FROM products
GROUP BY product_id;
MAX()priceELSE NULLROW_NUMBER()CASE + MAXCOUNT(CASE ...)CASECASEELSENULLSUM()AVG()COUNT()COUNT(*)COUNT(col)NULLWHEREGROUP BYCASEWHERECASECASEWHERECASEWHEREGROUP BYCASE