题目描述

(通过次数1,519 | 提交次数2,154,通过率70.52%)

表: Subscriptions
+-------------+------+
| Column Name | Type |
+-------------+------+
| account_id  | int  |
| start_date  | date |
| end_date    | date |
+-------------+------+
account_id 是此表的主键列。
此表的每一行都表示帐户订阅的开始和结束日期。
请注意,始终开始日期 < 结束日期。
表: Streams
+-------------+------+
| Column Name | Type |
+-------------+------+
| session_id  | int  |
| account_id  | int  |
| stream_date | date |
+-------------+------+
session_id是该表的主键列。
account_id是订阅表中的外键。
此表的每一行都包含与会话相关联的帐户和日期的信息。
编写SQL查询以报告在 2021 购买订阅但没有任何会话的帐 户数。
查询结果格式如下例所示。
示例1:
输入: 
Subscriptions table:
+------------+------------+------------+
| account_id | start_date | end_date   |
+------------+------------+------------+
| 9          | 2020-02-18 | 2021-10-30 |
| 3          | 2021-09-21 | 2021-11-13 |
| 11         | 2020-02-28 | 2020-08-18 |
| 13         | 2021-04-20 | 2021-09-22 |
| 4          | 2020-10-26 | 2021-05-08 |
| 5          | 2020-09-11 | 2021-01-17 |
+------------+------------+------------+
Streams table:
+------------+------------+-------------+
| session_id | account_id | stream_date |
+------------+------------+-------------+
| 14         | 9          | 2020-05-16  |
| 16         | 3          | 2021-10-27  |
| 18         | 11         | 2020-04-29  |
| 17         | 13         | 2021-08-08  |
| 19         | 4          | 2020-12-31  |
| 13         | 5          | 2021-01-05  |
+------------+------------+-------------+
输出: 
+----------------+
| accounts_count |
+----------------+
| 2              |
+----------------+
解释:用户 4 和 9 在 2021 没有会话。
用户 11 在 2021 没有订阅。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-accounts-that-did-not-stream
//测试数据
Create table If Not Exists Subscriptions (account_id int, start_date date, end_date date);
Create table If Not Exists Streams (session_id int, account_id int, stream_date date);

insert into Subscriptions (account_id, start_date, end_date) values ('9', '2020-02-18', '2021-10-30');
insert into Subscriptions (account_id, start_date, end_date) values ('3', '2021-09-21', '2021-11-13');
insert into Subscriptions (account_id, start_date, end_date) values ('11', '2020-02-28', '2020-08-18');
insert into Subscriptions (account_id, start_date, end_date) values ('13', '2021-04-20', '2021-09-22');
insert into Subscriptions (account_id, start_date, end_date) values ('4', '2020-10-26', '2021-05-08');
insert into Subscriptions (account_id, start_date, end_date) values ('5', '2020-09-11', '2021-01-17');

insert into Streams (session_id, account_id, stream_date) values ('14', '9', '2020-05-16');
insert into Streams (session_id, account_id, stream_date) values ('16', '3', '2021-10-27');
insert into Streams (session_id, account_id, stream_date) values ('18', '11', '2020-04-29');
insert into Streams (session_id, account_id, stream_date) values ('17', '13', '2021-08-08');
insert into Streams (session_id, account_id, stream_date) values ('19', '4', '2020-12-31');
insert into Streams (session_id, account_id, stream_date) values ('13', '5', '2021-01-05');

解题思路

Subscriptions表保存了每个账户的订阅时间区间。
Streams表保存了账户所有的会话数据。
题目要求:查询在2021年有购买订阅,但没有任何会话的账户数。
对于第一个条件:在2021年有购买订阅。因为账户的订阅时间是个区间,而2021年包含2021-01-01至2021-12-31的时间区间。
如何判断两个时间区间有交叉呢?
抽象一下:假如有两个时间区间(a1,b1)和(a2,b2),当两个区间有交叉时,必须同时满足a1<=b2、b1>=a2。
具体到本题目,要满足2021年有购买订阅,必须满足条件:start_date <= '2021-12-31' and end_date >= '2021-01-01'。
对于第二个条件:2021年没有任何会话。可以使用NOT IN或NOT EXISTS实现。

参考SQL

未特别说明的情况下,参考SQL为基于MySQL8.0实现。
select
    count(1) accounts_count
from Subscriptions a
where a.start_date <= '2021-12-31'
and a.end_date >= '2021-01-01'
and not exists (
    select 1
    from Streams b
    where a.account_id = b.account_id
    and b.stream_date between '2021-01-01' and '2021-12-31'
);
picture loss