目录
1. 力扣链接
2. 题目
3. 分析
4. 代码实现
5. 代码验证
6. 总结
1. 力扣链接
1225. 报告系统状态的连续日期 - 力扣(LeetCode)
2. 题目
表:
Failed
+--------------+---------+ | Column Name | Type | +--------------+---------+ | fail_date | date | +--------------+---------+ 该表主键为 fail_date (具有唯一值的列)。 该表包含失败任务的天数.表:
Succeeded
+--------------+---------+ | Column Name | Type | +--------------+---------+ | success_date | date | +--------------+---------+ 该表主键为 success_date (具有唯一值的列)。 该表包含成功任务的天数.系统 每天 运行一个任务。每个任务都独立于先前的任务。任务的状态可以是失败或是成功。
编写解决方案找出 2019-01-01 到 2019-12-31 期间任务连续同状态
period_state
的起止日期(start_date
和end_date
)。即如果任务失败了,就是失败状态的起止日期,如果任务成功了,就是成功状态的起止日期。最后结果按照起始日期
start_date
排序返回结果样例如下所示:
示例 1:
输入: 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 | +-------------------+ 输出: +--------------+--------------+--------------+ | 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-01 到 2019-12-31 的记录 从 2019-01-01 到 2019-01-03 所有任务成功,系统状态为 "succeeded"。 从 2019-01-04 到 2019-01-05 所有任务失败,系统状态为 "failed"。 从 2019-01-06 到 2019-01-06 所有任务成功,系统状态为 "succeeded"。
-- 建表语句
Create table If Not Exists Failed (fail_date date);
Create table If Not Exists Succeeded (success_date date);
Truncate table Failed;
insert into Failed (fail_date) values ('2018-12-28');
insert into Failed (fail_date) values ('2018-12-29');
insert into Failed (fail_date) values ('2019-01-04');
insert into Failed (fail_date) values ('2019-01-05');
Truncate table Succeeded;
insert into Succeeded (success_date) values ('2018-12-30');
insert into Succeeded (success_date) values ('2018-12-31');
insert into Succeeded (success_date) values ('2019-01-01');
insert into Succeeded (success_date) values ('2019-01-02');
insert into Succeeded (success_date) values ('2019-01-03');
insert into Succeeded (success_date) values ('2019-01-06');
3. 分析
确定状态:首先,我们需要增加状态列确定每一天的状态。如果某一天在
Succeeded
表中,则状态为succeeded
;如果在Failed
表中,则状态为failed
合并日期:我们需要将
Failed
和Succeeded
两个表中的日期合并到一个单一的日期列表中过滤日期范围:由于我们只关心2019年1月1日到2019年12月31日的记录,我们需要过滤掉这个范围之外的日期
确定等差数列一:我们按照时间进行排序,作为等差数列一
确定等差数列二:我们按照状态分组,对时间进行排序,作为等差数列二
确定连续:使用等差数列一减去等差数列二,差值相同则为同状态连续
确定周期:对于每个状态周期,我们需要确定其起始日期和结束日期。起始日期是状态连续开始的日期也就是分组后的最小日期,结束日期是状态连续结束的日期也就是分组后的最大日期
排序结果:最后,我们需要按照起始日期对结果进行排序
4. 代码实现
with t1 as(select'succeeded' period_state,success_date `date`from Succeededunionselect'failed' period_state,fail_date `date`from Failed
),t2 as(select *,row_number() over(order by `date`)-row_number() over(partition by period_state order by `date`) difffrom t1 where `date` between '2019-01-01' and '2019-12-31'
)select period_state,min(date) start_date,max(date) end_date
from t2
group by period_state,diff
order by start_date;
5. 代码验证
6. 总结
CTE (Common Table Expressions): 用于定义临时结果集,使复杂的查询更加清晰和易于管理。
UNION: 合并两个或多个SELECT语句的结果集,但去除重复的行。
ROW_NUMBER(): 窗口函数,用于为每个分区内的行分配一个唯一的序号。
PARTITION BY: 与窗口函数一起使用,将数据集划分为多个分区,每个分区独立进行计算。
ORDER BY: 在窗口函数中定义行的排序方式,确保序号分配的顺序。
GROUP BY: 将结果集的行分组,以便对每个组执行聚合函数。
MIN() and MAX(): 聚合函数,用于找出每个分组中的最小值和最大值。
ORDER BY: 对最终结果进行排序,确保输出的顺序性。
STRING ALIASING: 使用反引号为列名或表达式指定别名,特别是当列名包含特殊字符或空格时。