题目描述

(通过次数7,951 | 提交次数20,483,通过率38.82%)

动作表:Actions
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| user_id       | int     |
| post_id       | int     |
| action_date   | date    |
| action        | enum    |
| extra         | varchar |
+---------------+---------+
这张表没有主键,并有可能存在重复的行。
action 列的类型是 ENUM,可能的值为 ('view', 'like', 'reaction', 'comment', 'report', 'share')。
extra 列拥有一些可选信息,例如:报告理由(a reason for report)或反应类型(a type of reaction)等。

移除表:Removals
+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| post_id       | int     |
| remove_date   | date    | 
+---------------+---------+
这张表的主键是 post_id。
这张表的每一行表示一个被移除的帖子,原因可能是由于被举报或被管理员审查。

编写一段 SQL 来查找:在被报告为垃圾广告(extra='spam')的帖子中,被移除的帖子的每日平均占比,四舍五入到小数点后 2 位。
以 任意顺序 返回结果表。

查询结果的格式如下。
示例 1:
输入:
Actions table:
+---------+---------+-------------+--------+--------+
| user_id | post_id | action_date | action | extra  |
+---------+---------+-------------+--------+--------+
| 1       | 1       | 2019-07-01  | view   | null   |
| 1       | 1       | 2019-07-01  | like   | null   |
| 1       | 1       | 2019-07-01  | share  | null   |
| 2       | 2       | 2019-07-04  | view   | null   |
| 2       | 2       | 2019-07-04  | report | spam   |
| 3       | 4       | 2019-07-04  | view   | null   |
| 3       | 4       | 2019-07-04  | report | spam   |
| 4       | 3       | 2019-07-02  | view   | null   |
| 4       | 3       | 2019-07-02  | report | spam   |
| 5       | 2       | 2019-07-03  | view   | null   |
| 5       | 2       | 2019-07-03  | report | racism |
| 5       | 5       | 2019-07-03  | view   | null   |
| 5       | 5       | 2019-07-03  | report | racism |
+---------+---------+-------------+--------+--------+
Removals table:
+---------+-------------+
| post_id | remove_date |
+---------+-------------+
| 2       | 2019-07-20  |
| 3       | 2019-07-18  |
+---------+-------------+
输出:
+-----------------------+
| average_daily_percent |
+-----------------------+
| 75.00                 |
+-----------------------+
解释:
2019-07-04 的垃圾广告移除率是 50%,因为有两张帖子被报告为垃圾广告,但只有一个得到移除。
2019-07-02 的垃圾广告移除率是 100%,因为有一张帖子被举报为垃圾广告并得到移除。
其余几天没有收到垃圾广告的举报,因此平均值为:(50 + 100) / 2 = 75%
注意,输出仅需要一个平均值即可,我们并不关注移除操作的日期。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/reported-posts-ii

//测试数据
Create table If Not Exists Actions (user_id int, post_id int, action_date date, action ENUM('view', 'like', 'reaction', 'comment', 'report', 'share'), extra varchar(10));
create table if not exists Removals (post_id int, remove_date date);

insert into Actions (user_id, post_id, action_date, action, extra) values ('1', '1', '2019-07-01', 'view', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('1', '1', '2019-07-01', 'like', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('1', '1', '2019-07-01', 'share', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('2', '2', '2019-07-04', 'view', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('2', '2', '2019-07-04', 'report', 'spam');
insert into Actions (user_id, post_id, action_date, action, extra) values ('3', '4', '2019-07-04', 'view', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('3', '4', '2019-07-04', 'report', 'spam');
insert into Actions (user_id, post_id, action_date, action, extra) values ('4', '3', '2019-07-02', 'view', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('4', '3', '2019-07-02', 'report', 'spam');
insert into Actions (user_id, post_id, action_date, action, extra) values ('5', '2', '2019-07-03', 'view', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('5', '2', '2019-07-03', 'report', 'racism');
insert into Actions (user_id, post_id, action_date, action, extra) values ('5', '5', '2019-07-03', 'view', 'None');
insert into Actions (user_id, post_id, action_date, action, extra) values ('5', '5', '2019-07-03', 'report', 'racism');

insert into Removals (post_id, remove_date) values ('2', '2019-07-20');
insert into Removals (post_id, remove_date) values ('3', '2019-07-18');

解题思路

这是一道中等难度的题目,说实话并不难。但通过率只有38%。在我的印象中,应该是我历史推文中最低的。
至于为什么会出现这种极端情况,我认为还是题目描述的有点不清不楚。
对源表Actions的介绍不是很全面,特别是对extra字段含义的介绍。
另外,官方原题目描述中也没有对怎么判定帖子被报告为垃圾广告进行说明。为方便理解,我对原题目描述进行了补充。
现在我们来看题目本身。
Removals表中保存了所有被移除的帖子及移除时间。很明显,一个帖子只能被移除一次。
Actions表中保存了用户对帖子所做的动作记录。同一天,同一用户对同一帖子可以做出多个动作。其中extra=spam表示报告帖子为垃圾广告。当然,被报告为垃圾广告的帖子,并不一定会被全部移除。
题目要求:查找在被报告为垃圾广告的帖子中,被移除的帖子的每日平均占比。
既然要求每日平均占比,那么就需要计算出每日的分子(被移除的帖子)和分母(被报告为垃圾广告的帖子),然后计算出每日的占比,最后再求每日的平均值。
所以,可以使用Actions表左关联Removals,得到一张大宽表。从表中可以知道每个帖子是否被报告为垃圾广告,以及是否被移除。
剩下的,就是分别计算出每日不同情况的帖子数,得出每日占比,最后返回平均值即可。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。

select 
    round(avg(daily_percent)*100,2) average_daily_percent
from (
    select
        count(distinct b.post_id)/count(distinct a.post_id) daily_percent
    from Actions a
    left join Removals b
    on a.post_id = b.post_id
    where a.extra = 'spam'
    group by a.action_date
)a;
picture loss