【SQL高频练习带刷】day20:补充习题

题目一:寻找没有被执行的任务对

题目要求:

编写解决方案报告没有被执行的(主任务,子任务)对,即没有被执行的(task_id, subtask_id)。

以 任何顺序 返回即可。

1767. 寻找没有被执行的任务对 - 力扣(LeetCode)

表结构:

运行结果示例:

思路:

        本题难度不大,很容易想到解决办法:列出所有子任务,再排除掉已经完成的子任务即可,但是如何列出所有子任务呢(当然可以使用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 升序排列

1831. 每天的最大交易 - 力扣(LeetCode)

表结构:

运行结果示例:

思路:

        同样是使用一个子查询,查找日期和交易金额等于当天最多交易金额的数据,注意本题给的时间是具体时间,我们要用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 排序。

1412. 查找成绩处于中游的学生 - 力扣(LeetCode)

表结构:

运行结果示例:

思路:

        我们首先找到所有科目对应的最高分和最低分,再从表中找到每门科目最高分、最低分对应的学生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 降序 排列。

1532. 最近的三笔订单 - 力扣(LeetCode)

表结构:

运行结果示例:

思路:

        连续题目大多数都是用排名窗口函数解决,本题也是如此,使用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 排序

1225. 报告系统状态的连续日期 - 力扣(LeetCode)

表结构:

运行结果示例:

思路:

        将日期分组,用一个数(日期)减去它的排名,会得到一个相同的数。分别对 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;

猜你喜欢

转载自blog.csdn.net/Liu_y_xin/article/details/141911644