订阅更新

好友申请总体通过率:分子分母各自去重

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

LeetCode 597 · 去重计数、除零处理

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

面试怎么回答

分子是去重后的通过对数,分母是去重后的申请对数,两边各自 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。
刷题进度保存在当前浏览器