题目一:寻找没有被执行的任务对
题目要求:
编写解决方案报告没有被执行的(主任务,子任务)对,即没有被执行的(task_id, subtask_id)。
以 任何顺序 返回即可。
表结构:
运行结果示例:
思路:
本题难度不大,很容易想到解决办法:列出所有子任务,再排除掉已经完成的子任务即可,但是如何列出所有子任务呢(当然可以使用union 手动实现,不嫌麻烦就kuku列举就完了,简单粗暴)。这时就用到了递归。关于递归的详细用法,这里就不详细讲述了。
运行代码示例:
with recursive a as (
SELECT
task_id,
1 as subtask_id,
subtasks_count
FROM Tasks
UNION ALL
SELECT
t.task_id,
t.subtask_id + 1 as c,
t.subtasks_count
FROM a t
WHERE
subtask_id < t.subtasks_count
)
select task_id, subtask_id
from a
WHERE (task_id, subtask_id) not IN (
SELECT
task_id,
subtask_id
FROM Executed
)
题目二:每天的最大交易
题目要求:
编写一个解决方案,报告每天交易金额
amount
最大 的交易 ID 。如果一天中有多个这样的交易,返回这些交易的 ID 。返回结果根据
transaction_id
升序排列。
表结构:
运行结果示例:
思路:
同样是使用一个子查询,查找日期和交易金额等于当天最多交易金额的数据,注意本题给的时间是具体时间,我们要用date()函数把日期取出来。
运行代码示例:
select transaction_id
from Transactions
where (date(day),amount) in (
select date(day),max(amount) as m
from Transactions
group by date(day)
)
order by transaction_id
题目三:查找成绩处于中游的学生
题目要求:
成绩处于中游的学生是指至少参加了一次测验, 且得分既不是最高分也不是最低分的学生。
编写解决方案,找出在 所有 测验中都处于中游的学生
(student_id, student_name)
。不要返回从来没有参加过测验的学生。返回结果表按照
student_id
排序。
表结构:
运行结果示例:
思路:
我们首先找到所有科目对应的最高分和最低分,再从表中找到每门科目最高分、最低分对应的学生id,最后找到其他学生id就可以了。这里也可以连接临时表和主表,直接使用not in查找不在上游和下游的学生id,减少一次子查询。
运行代码示例:
select distinct e.student_id,student_name from Exam e
join Student s
on s.student_id = e.student_id
where e.student_id not in (
select distinct student_id from Exam where (exam_id,score) in (
select exam_id,max(score) as score
from Exam
group by exam_id
union
select exam_id,min(score) as score
from Exam
group by exam_id
)
)
order by student_id
题目四:最近的三笔订单
题目要求:
写一个解决方案,找到每个用户的最近三笔订单。如果用户的订单少于 3 笔,则返回他的全部订单。
返回的结果按照
customer_name
升序 排列。如果有相同的排名,则按照customer_id
升序 排列。如果排名还有相同,则按照order_date
降序 排列。
表结构:
运行结果示例:
思路:
连续题目大多数都是用排名窗口函数解决,本题也是如此,使用dense_rank() over (partition by O.customer_id order by order_date desc) 进行排序,找到排序在前三的订单即可。
运行代码示例:
SELECT name AS customer_name, customer_id, order_id, order_date
FROM
(
SELECT O.customer_id, name, order_id, order_date, dense_rank() over (partition by O.customer_id order by order_date desc) rk
FROM Orders O LEFT JOIN Customers C ON O.customer_id=C.customer_id
) t
WHERE rk<=3
ORDER BY customer_name, customer_id, order_date DESC
题目五:报告系统连续状态的日期
题目要求:
系统 每天 运行一个任务。每个任务都独立于先前的任务。任务的状态可以是失败或是成功。
编写解决方案找出 2019-01-01 到 2019-12-31 期间任务连续同状态
period_state
的起止日期(start_date
和end_date
)。即如果任务失败了,就是失败状态的起止日期,如果任务成功了,就是成功状态的起止日期。最后结果按照起始日期
start_date
排序
表结构:
运行结果示例:
思路:
将日期分组,用一个数(日期)减去它的排名,会得到一个相同的数。分别对 failed 和 succeeded 计算连续区间,在使用 union 连接两次结果
运行代码示例:
select
'failed' period_state,
min(fail_date) start_date,
max(fail_date) end_date
from (
select
fail_date,
subdate(fail_date, row_number() over()) first_date
from failed where extract(year from fail_date) = 2019
) t1 group by first_date
union
select
'succeeded' period_state,
min(success_date) start_date,
max(success_date) end_date
from (
select
success_date,
subdate(success_date, row_number() over()) first_date
from succeeded where extract(year from success_date) = 2019
) t2 group by first_date order by start_date;