订阅更新

广告点击率 CTR:分母为 0 时记为 0

SQL 实战 123 题 · 第 93 题 简单 约 2 分钟读完

LeetCode 1322 · 条件计数、除零处理、多字段排序

本文目录
  1. 面试怎么回答
  2. 题意
  3. 表结构
  4. 思路
  5. 参考解法
  6. 易错点

面试怎么回答

按 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。
刷题进度保存在当前浏览器