Bootstrap

LeetCode-SQL(五)

以下题目均来自力扣

81、1225.报告系统状态的连续日期

难度:★★★★★

Table: Failed

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| fail_date    | date    |
+--------------+---------+
该表主键为 fail_date。
该表包含失败任务的天数.

Table: Succeeded

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
| success_date | date    |
+--------------+---------+
该表主键为 success_date。
该表包含成功任务的天数.

系统 每天 运行一个任务。每个任务都独立于先前的任务。任务的状态可以是失败或是成功。

编写一个 SQL 查询 2019-01-012019-12-31 期间任务连续同状态 period_state 的起止日期(start_dateend_date)。即如果任务失败了,就是失败状态的起止日期,如果任务成功了,就是成功状态的起止日期。

最后结果按照起始日期 start_date 排序

查询结果样例如下所示:

Failed table:
+-------------------+
| fail_date         |
+-------------------+
| 2018-12-28        |
| 2018-12-29        |
| 2019-01-04        |
| 2019-01-05        |
+-------------------+

Succeeded table:
+-------------------+
| success_date      |
+-------------------+
| 2018-12-30        |
| 2018-12-31        |
| 2019-01-01        |
| 2019-01-02        |
| 2019-01-03        |
| 2019-01-06        |
+-------------------+


Result table:
+--------------+--------------+--------------+
| period_state | start_date   | end_date     |
+--------------+--------------+--------------+
| succeeded    | 2019-01-01   | 2019-01-03   |
| failed       | 2019-01-04   | 2019-01-05   |
| succeeded    | 2019-01-06   | 2019-01-06   |
+--------------+--------------+--------------+

结果忽略了 2018 年的记录,因为我们只关心从 2019-01-012019-12-31 的记录
从 2019-01-012019-01-03 所有任务成功,系统状态为 "succeeded"。
从 2019-01-042019-01-05 所有任务失败,系统状态为 "failed"。
从 2019-01-062019-01-06 所有任务成功,系统状态为 "succeeded"
解答:
两表进行组合
select 'failed' period_state,fail_date dt from Failed where fail_date between '2019-01-01' and '2019-12-31'
union all
select 'succeeded' period_state,success_date dt from Succeeded where success_date between '2019-01-01' and '2019-12-31'
开窗
select period_state,dt,rank() over(partition by period_state order by dt) rk
from
(select 'failed' period_state,fail_date dt from Failed where fail_date between '2019-01-01' and '2019-12-31'
union all
select 'succeeded' period_state,success_date dt from Succeeded where success_date between '2019-01-01' and '2019-12-31') t
计算
select period_state,dt,date_sub(dt,interval rk day) dt1 from
(select period_state,dt,rank() over(partition by period_state order by dt) rk
from
(select 'failed' period_state,fail_date dt from Failed where fail_date between '2019-01-01' and '2019-12-31'
union all
select 'succeeded' period_state,success_date dt from Succeeded where success_date between '2019-01-01' and '2019-12-31') t) k order by dt1
分组求日期
select period_state,min(dt) start_date,max(dt) end_date
from
(select period_state,dt,date_sub(dt,interval rk day) dt1 from
(select period_state,dt,rank() over(partition by period_state order by dt) rk
from
(select 'failed' period_state,fail_date dt from Failed where fail_date between '2019-01-01' and '2019-12-31'
union all
select 'succeeded' period_state,success_date dt from Succeeded where success_date between '2019-01-01' and '2019-12-31') t) k order by dt1) tmp
group by dt1,period_state order by start_date
拓展:连续问题

连续问题一般都是进行开窗排序,然后相减得到相同的就是连续的


82、1241.每个帖子的评论数

难度:★★☆☆☆

Submissions 结构如下:

+---------------+----------+
| 列名           | 类型     |
+---------------+----------+
| sub_id        | int      |
| parent_id     | int      |
+---------------+----------+
上表没有主键, 所以可能会出现重复的行。
每行可以是一个帖子或对该帖子的评论。
如果是帖子的话,parent_id 就是 null。
对于评论来说,parent_id 就是表中对应帖子的 sub_id。

编写 SQL 语句以查找每个帖子的评论数。

结果表应包含帖子的 post_id 和对应的评论数 number_of_comments 并且按 post_id 升序排列。

Submissions 可能包含重复的评论。您应该计算每个帖子的唯一评论数。

Submissions 可能包含重复的帖子。您应该将它们视为一个帖子。

查询结果格式如下例所示:

Submissions table:
+---------+------------+
| sub_id  | parent_id  |
+---------+------------+
| 1       | Null       |
| 2       | Null       |
| 1       | Null       |
| 12      | Null       |
| 3       | 1          |
| 5       | 2          |
| 3       | 1          |
| 4       | 1          |
| 9       | 1          |
| 10      | 2          |
| 6       | 7          |
+---------+------------+

结果表:
+---------+--------------------+
| post_id | number_of_comments |
+---------+--------------------+
| 1       | 3                  |
| 2       | 2                  |
| 12      | 0                  |
+---------+--------------------+

表中 ID 为 1 的帖子有 ID 为 349 的三个评论。表中 ID 为 3 的评论重复出现了,所以我们只对它进行了一次计数。
表中 ID 为 2 的帖子有 ID 为 510 的两个评论。
ID 为 12 的帖子在表中没有评论。
表中 ID 为 6 的评论是对 ID 为 7 的已删除帖子的评论,因此我们将其忽略。
解答:
找出是帖子的id
select distinct sub_id post_id from Submissions where parent_id is null;
上表和Submissions进行左连接
select distinct post_id,sub_id
from (select distinct sub_id post_id from Submissions where parent_id is null) t
left join Submissions s on t.post_id=s.parent_id
;
分组求数
select post_id,sum(if(sub_id is null,0,1)) number_of_comments
from (select distinct post_id,sub_id
from (select distinct sub_id post_id from Submissions where parent_id is null) t
left join Submissions s on t.post_id=s.parent_id) r group by post_id order by post_id
;

83、1251.平均售价

难度:★★☆☆☆

Table: Prices

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| start_date    | date    |
| end_date      | date    |
| price         | int     |
+---------------+---------+
(product_id,start_date,end_date) 是 Prices 表的主键。
Prices 表的每一行表示的是某个产品在一段时期内的价格。
每个产品的对应时间段是不会重叠的,这也意味着同一个产品的价格时段不会出现交叉。

Table: UnitsSold

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| product_id    | int     |
| purchase_date | date    |
| units         | int     |
+---------------+---------+
UnitsSold 表没有主键,它可能包含重复项。
UnitsSold 表的每一行表示的是每种产品的出售日期,单位和产品 id。

编写SQL查询以查找每种产品的平均售价。
average_price 应该四舍五入到小数点后两位。
查询结果格式如下例所示:

Prices table:
+------------+------------+------------+--------+
| product_id | start_date | end_date   | price  |
+------------+------------+------------+--------+
| 1          | 2019-02-17 | 2019-02-28 | 5      |
| 1          | 2019-03-01 | 2019-03-22 | 20     |
| 2          | 2019-02-01 | 2019-02-20 | 15     |
| 2          | 2019-02-21 | 2019-03-31 | 30     |
+------------+------------+------------+--------+
 
UnitsSold table:
+------------+---------------+-------+
| product_id | purchase_date | units |
+------------+---------------+-------+
| 1          | 2019-02-25    | 100   |
| 1          | 2019-03-01    | 15    |
| 2          | 2019-02-10    | 200   |
| 2          | 2019-03-22    | 30    |
+------------+---------------+-------+

Result table:
+------------+---------------+
| product_id | average_price |
+------------+---------------+
| 1          | 6.96          |
| 2          | 16.96         |
+------------+---------------+
平均售价 = 产品总价 / 销售的产品数量。
产品 1 的平均售价 = ((100 * 5)+(15 * 20) )/ 115 = 6.96
产品 2 的平均售价 = ((200 * 15)+(30 * 30) )/ 230 = 16.96
解答:
两表进行连接
select u.product_id product_id,units*price price,units
from UnitsSold u join Prices p on u.product_id=p.product_id where
u.purchase_date between p.start_date and p.end_date
;
分组求平均值
select product_id,round(sum(price)/sum(units),2) average_price from(
select u.product_id product_id,units*price price,units
from UnitsSold u join Prices p on u.product_id=p.product_id where
u.purchase_date between p.start_date and p.end_date) t group by product_id
;

84、1264.页面推荐

难度:★★★☆☆

朋友关系列表: Friendship

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| user1_id      | int     |
| user2_id      | int     |
+---------------+---------+
这张表的主键是 (user1_id, user2_id)。
这张表的每一行代表着 user1_id 和 user2_id 之间存在着朋友关系。

喜欢列表: Likes

+-------------+---------+
| Column Name | Type    |
+-------------+---------+
| user_id     | int     |
| page_id     | int     |
+-------------+---------+
这张表的主键是 (user_id, page_id)。
这张表的每一行代表着 user_id 喜欢 page_id。

写一段 SQL 向user_id = 1 的用户,推荐其朋友们喜欢的页面。不要推荐该用户已经喜欢的页面。

你返回的结果中不应当包含重复项。

返回结果的格式如下例所示:

Friendship table:
+----------+----------+
| user1_id | user2_id |
+----------+----------+
| 1        | 2        |
| 1        | 3        |
| 1        | 4        |
| 2        | 3        |
| 2        | 4        |
| 2        | 5        |
| 6        | 1        |
+----------+----------+
 
Likes table:
+---------+---------+
| user_id | page_id |
+---------+---------+
| 1       | 88      |
| 2       | 23      |
| 3       | 24      |
| 4       | 56      |
| 5       | 11      |
| 6       | 33      |
| 2       | 77      |
| 3       | 77      |
| 6       | 88      |
+---------+---------+

Result table:
+------------------+
| recommended_page |
+------------------+
| 23               |
| 24               |
| 56               |
| 33               |
| 77               |
+------------------+
用户1 同 用户2, 3, 4, 6 是朋友关系。
推荐页面为: 页面23 来自于 用户2, 页面24 来自于 用户3, 页面56 来自于 用户3 以及 页面33 来自于 用户6。
页面77 同时被 用户2 和 用户3 推荐。
页面88 没有被推荐,因为 用户1 已经喜欢了它。
解答:
求出用户1的朋友
select user1_id from Friendship where user2_id=1
union all
select user2_id from Friendship where user1_id=1
找到用户1朋友喜欢的
select distinct page_id
from Likes where user_id in (select user1_id from Friendship where user2_id=1
union all
select user2_id from Friendship where user1_id=1)
找到用户1喜欢的
select page_id from Likes where user_id=1
去除掉用户1喜欢的
select page_id
from (select distinct page_id
from Likes where user_id in (select user1_id from Friendship where user2_id=1
union all
select user2_id from Friendship where user1_id=1)) t where page_id not in (select page_id from Likes where user_id=1)

85、1280.学生们参加各科测试的次数

难度:★★☆☆☆

学生表: Students

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| student_id    | int     |
| student_name  | varchar |
+---------------+---------+
主键为 student_id(学生ID),该表内的每一行都记录有学校一名学生的信息。

科目表: Subjects

+--------------+---------+
| Column Name  | Type    |
+--------------+---------+
;