好友申请总体通过率:分子分母各自去重
LeetCode 597 · 去重计数、除零处理
面试怎么回答
分子是去重后的通过对数,分母是去重后的申请对数,两边各自 COUNT(DISTINCT 两列),用标量子查询相除,IFNULL 处理分母为 0,再 ROUND 两位。进阶按月统计时,把两边分别按月分组后再关联,注意某月只有申请没有通过的情况要用外连接。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
题意
申请表记录发起人、接收人和日期,通过表记录申请人、通过人和日期。求总体通过率 = 去重后的通过数 / 去重后的申请数,保留两位小数;没有任何申请时返回 0.00。
表结构
- friend_request:sender_id、send_to_id、request_date
- request_accepted:requester_id、accepter_id、accept_date
思路
同一对人可能多次申请、多次通过,所以分子分母都要按「人员对」去重后再计数。两个计数来自不同的表,各自写成标量子查询再相除。分母为 0 时除法得到 NULL,用 IFNULL 兜底成 0。
参考解法
select
round(
ifnull(
(select count(*) from (select distinct requester_id, accepter_id from request_accepted) as A)
/
(select count(*) from (select distinct sender_id, send_to_id from friend_request) as B),
0)
, 2) as accept_rate;
另一种写法:MySQL 里可以直接对两列去重计数
SELECT ROUND(IFNULL(
(SELECT COUNT(DISTINCT requester_id, accepter_id) FROM request_accepted) /
(SELECT COUNT(DISTINCT sender_id, send_to_id) FROM friend_request), 0), 2) AS accept_rate
易错点
- 只对一边去重,比例会偏高或偏低。
COUNT(DISTINCT a, b)是 MySQL 的写法,其他数据库要先子查询 DISTINCT 再 COUNT。- 没有申请时要返回 0.00 而不是 NULL。