广告点击率 CTR:分母为 0 时记为 0
LeetCode 1322 · 条件计数、除零处理、多字段排序
面试怎么回答
按 ad_id 分组,ROUND(IFNULL(SUM(action = 'Clicked') / (SUM(action = 'Clicked') + SUM(action = 'Viewed')) * 100, 0), 2),排序写 ctr DESC, ad_id。条件放在聚合里而不是 WHERE 里,才能保留只被忽略的广告。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
广告表记录用户对广告的行为:点击、查看或忽略。点击率 = 点击数 / (点击数 + 查看数) × 100,分母为 0 时点击率记为 0,保留两位小数,按点击率降序、广告 ID 升序排列。
表结构
- Ads:ad_id、user_id、action(Clicked / Viewed / Ignored);(ad_id, user_id) 为主键
思路
按广告分组,用条件计数分别求点击数和查看数。只有被忽略过的广告分母为 0,除法结果为 NULL,用 IFNULL 变成 0。不要在 WHERE 里过滤掉 Ignored,否则只被忽略过的广告会整个消失。
参考解法
写法 1:一次分组搞定(推荐)
SELECT ad_id,
ROUND(IFNULL(SUM(action = 'Clicked') /
(SUM(action = 'Clicked') + SUM(action = 'Viewed')) * 100, 0), 2) AS ctr
FROM Ads
GROUP BY ad_id
ORDER BY ctr DESC, ad_id ASC;
写法 2:先过滤再左关联补回只被忽略的广告
select a.ad_id,ifnull(ctr,0) ctr
from Ads a
left join (
select ad_id,round(sum(if(action='Clicked',1,0))/count(*)*100,2) ctr
from Ads
where action !='Ignored'
group by ad_id
)t1
on a.ad_id= t1.ad_id
group by ad_id,ctr
order by ctr desc,ad_id
易错点
- WHERE action != 'Ignored' 会让只被忽略过的广告从结果里消失。
- 分母为 0 时除法返回 NULL,要转成 0。