SQL题——连续问题

1.连续问题的统一思路

核心思想:连续变量−排序变量=常数C,根据常数C分组求和,即可判断连续次数

1.首先要有连续的参考列,如果没有,则需要自己构造
2.用row_number()对目标做排序,比如日期
3.排序后做diff,连续的diff一定相同,然后按diff取目标结果即可

2.相关题目

1285 找到连续区间的开始和结束数字

表:Logs

+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| log_id        | int     |
+---------------+---------+

id 是上表具有唯一值的列。
上表的每一行包含日志表中的一个 ID。

编写解决方案,得到 Logs 表中的连续区间的开始数字和结束数字。

返回结果表按照 start_id 排序。

结果格式如下面的例子。

示例 1:

输入:
Logs 表:

+------------+
| log_id     |
+------------+
| 1          |
| 2          |
| 3          |
| 7          |
| 8          |
| 10         |
+------------+

输出:

+------------+--------------+
| start_id   | end_id       |
+------------+--------------+
| 1          | 3            |
| 7          | 8            |
| 10         | 10           |
+------------+--------------+

解释:
结果表应包含 Logs 表中的所有区间。
从 1 到 3 在表中。
从 4 到 6 不在表中。
从 7 到 8 在表中。
9 不在表中。
10 在表中。

答案:

select   min(log_id) as start_id 
        ,max(log_id) as end_id
from 
    (select *
            ,log_id - row_number() over(order by log_id) as diff
    from logs ) t0
group by diff
order by start_id
;

2173 最多连胜的次数

表: Matches

+-------------+------+
| Column Name | Type |
+-------------+------+
| player_id   | int  |
| match_day   | date |
| result      | enum |
+-------------+------+

(player_id, match_day) 是该表的主键(具有唯一值的列的组合)。
每一行包括了:参赛选手 id、 比赛时间、 比赛结果。
比赛结果(result)的枚举类型为 (‘Win’, ‘Draw’, ‘Lose’)。

选手的 连胜数 是指连续获胜的次数,且没有被平局或输球中断。

编写解决方案来计算每个参赛选手最多的连胜数。

结果可以以 任何顺序 返回。

结果格式如下例所示:

示例 1:

输入:
Matches 表:

+-----------+------------+--------+
| player_id | match_day  | result |
+-----------+------------+--------+
| 1         | 2022-01-17 | Win    |
| 1         | 2022-01-18 | Win    |
| 1         | 2022-01-25 | Win    |
| 1         | 2022-01-31 | Draw   |
| 1         | 2022-02-08 | Win    |
| 2         | 2022-02-06 | Lose   |
| 2         | 2022-02-08 | Lose   |
| 3         | 2022-03-30 | Win    |
+-----------+------------+--------+

输出:

+-----------+----------------+
| player_id | longest_streak |
+-----------+----------------+
| 1         | 3              |
| 2         | 0              |
| 3         | 1              |
+-----------+----------------+

解释:
Player 1:
从 2022-01-17 到 2022-01-25, player 1连续赢了三场比赛。
2022-01-31, player 1 平局.
2022-02-08, player 1 赢了一场比赛。
最多连胜了三场比赛。

Player 2:
从 2022-02-06 到 2022-02-08, player 2 输了两场比赛。
最多连赢了0场比赛。

Player 3:
2022-03-30, player 3 赢了一场比赛。
最多连赢了一场比赛。

答案:

select a.player_id
        ,IFNULL(b.longest_streak, 0) as longest_streak
from (
    select distinct player_id as player_id
    from matches
) a
left join 
(
     select player_id
    ,max(cnt) as longest_streak 
    from
        (select player_id
                ,diff
                ,count(1) as cnt
        from
            (select *
                    ,rn1 - rn2 as diff
            from
                (select *
                        ,row_number() over(partition by player_id order by match_day) as rn1
                        ,row_number() over(partition by player_id, result order by match_day) as rn2
                from matches) t
            )t1
        where  result = 'win'
        group by  player_id
                ,diff
        ) t2
    group by player_id
) b
on a.player_id = b.player_id
;


1454 活跃用户

表 Accounts:


+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| id            | int     |
| name          | varchar |
+---------------+---------+

id 是该表主键(具有唯一值的列)
该表包含账户 id 和账户的用户名.

表 Logins:


+---------------+---------+
| Column Name   | Type    |
+---------------+---------+
| id            | int     |
| login_date    | date    |
+---------------+---------+

该表可能包含重复项.
该表包含登录用户的账户 id 和登录日期. 用户也许一天内登录多次.

活跃用户 是指那些至少连续 5 天登录账户的用户。

编写解决方案, 找到 活跃用户 的 id 和 name。

返回的结果表按照 id 排序 。

结果表格式如下例所示。

示例 1:

输入:
Accounts 表:

+----+----------+
| id | name     |
+----+----------+
| 1  | Winston  |
| 7  | Jonathan |
+----+----------+

Logins 表:

+----+------------+
| id | login_date |
+----+------------+
| 7  | 2020-05-30 |
| 1  | 2020-05-30 |
| 7  | 2020-05-31 |
| 7  | 2020-06-01 |
| 7  | 2020-06-02 |
| 7  | 2020-06-02 |
| 7  | 2020-06-03 |
| 1  | 2020-06-07 |
| 7  | 2020-06-10 |
+----+------------+

输出:

+----+----------+
| id | name     |
+----+----------+
| 7  | Jonathan |
+----+----------+

解释:
id = 1 的用户 Winston 仅仅在不同的 2 天内登录了 2 次, 所以, Winston 不是活跃用户.
id = 7 的用户 Jonathon 在不同的 6 天内登录了 7 次, , 6 天中有 5 天是连续的, 所以, Jonathan 是活跃用户.

答案:


select  distinct t3.id
        ,t4.name
from
    (select id
        ,subdate(login_date, rn) as first_date
    from
        (select id
                ,login_date
                ,row_number() over(partition by id order by login_date) as rn
        from
            (select distinct id
                    ,login_date
            from logins ) t1
        ) t2
    group by id
            ,first_date
    having count(*) >= 5) t3
left join accounts t4
on t3.id = t4.id;

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

表: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”。

答案:

select *
from
(
    select  'failed' as period_state 
            ,MIN(fail_date) AS start_date
            ,MAX(fail_date) AS end_date
    from
        (   select fail_date
                ,subdate(fail_date, rn) as frist_date
            from 
                (select fail_date
                        ,row_number() over(order by fail_date) as rn
                from failed 
                where fail_date between '2019-01-01' and '2019-12-31'
            ) t0
    ) t1
    group by frist_date
    union all
    select  'succeeded' as period_state 
            ,MIN(success_date) AS start_date
            ,MAX(success_date) AS end_date
    from
        (   select  success_date
                    ,subdate(success_date, rn) as frist_date
            from 
            (   select success_date
                        ,row_number() over(order by success_date) as rn
                from Succeeded  
                where success_date between '2019-01-01' and '2019-12-31'
            ) t0
    ) t1
    group by frist_date
) t
order by start_date 


2292 连续两年有3个及以上订单的产品

表: Orders

+---------------+------+
| Column Name   | Type |
+---------------+------+
| order_id      | int  |
| product_id    | int  |
| quantity      | int  |
| purchase_date | date |
+---------------+------+

order_id 包含唯一值。
该表中的每一行都包含订单 ID、购买的产品 ID、数量和购买日期。

编写解决方案,获取连续两年订购三次或三次以上的所有产品的 id。

以 任意顺序 返回结果表。

结果格式示例如下。

示例 1:

输入:
Orders 表:

+----------+------------+----------+---------------+
| order_id | product_id | quantity | purchase_date |
+----------+------------+----------+---------------+
| 1        | 1          | 7        | 2020-03-16    |
| 2        | 1          | 4        | 2020-12-02    |
| 3        | 1          | 7        | 2020-05-10    |
| 4        | 1          | 6        | 2021-12-23    |
| 5        | 1          | 5        | 2021-05-21    |
| 6        | 1          | 6        | 2021-10-11    |
| 7        | 2          | 6        | 2022-10-11    |
+----------+------------+----------+---------------+

输出:

+------------+
| product_id |
+------------+
| 1          |
+------------+

解释:
产品 1 在 2020 年和 2021 年都分别订购了三次。由于连续两年订购了三次,所以我们将其包含在答案中。
产品 2 在 2022 年订购了一次。我们不把它包括在答案中。

答案:

select distinct product_id
from 
    (select product_id
            ,ord_date
            ,ord_date - row_number() over(partition by product_id order by ord_date) as first_year
    from
        (
            select date_format(purchase_date, '%Y') as ord_date
                ,product_id
                ,count(order_id) as ord_cnt
            from orders 
            group by product_id
                    ,date_format(purchase_date, '%Y')
            having count(order_id) >= 3
        ) t0
    ) t1
group by product_id 
        ,first_year
having count(*) > 1;

相关推荐

  1. SQL——连续问题

    2024-06-12 11:28:01       20 阅读
  2. SQL实用技巧】-- 连续N天登陆问题

    2024-06-12 11:28:01       45 阅读
  3. SQL连续

    2024-06-12 11:28:01       72 阅读
  4. SQL面试挑战03:奖金瓜分问题(拼多多)

    2024-06-12 11:28:01       58 阅读
  5. 记录解决问题--redis ssl连接

    2024-06-12 11:28:01       35 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-06-12 11:28:01       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-06-12 11:28:01       106 阅读
  3. 在Django里面运行非项目文件

    2024-06-12 11:28:01       87 阅读
  4. Python语言-面向对象

    2024-06-12 11:28:01       96 阅读

热门阅读

  1. 【编译安卓ROM常见错误和注意事项】

    2024-06-12 11:28:01       25 阅读
  2. C#(C Sharp)学习笔记_继承【十七】

    2024-06-12 11:28:01       35 阅读
  3. C++中的装饰器模式

    2024-06-12 11:28:01       25 阅读
  4. fabric.util.enlivenObjects是什么意思

    2024-06-12 11:28:01       23 阅读
  5. Mongodb篇(中)(3)

    2024-06-12 11:28:01       27 阅读
  6. 数据仓库之分层存储

    2024-06-12 11:28:01       26 阅读
  7. PHP框架详解-symfony框架

    2024-06-12 11:28:01       24 阅读
  8. Kotlin 协程:从基础概念到开发实践

    2024-06-12 11:28:01       30 阅读
  9. 架构演化过程中,如何确保核心功能不受影响?

    2024-06-12 11:28:01       24 阅读
  10. 如何在小程序中实现页面之间的跳转

    2024-06-12 11:28:01       25 阅读
  11. Web前端推送功能:深入剖析与应用实践

    2024-06-12 11:28:01       26 阅读
  12. Android——WiFi

    2024-06-12 11:28:01       24 阅读
  13. 等保测评在防范数据泄露中的关键作用

    2024-06-12 11:28:01       31 阅读