大厂面试SQL连续类型问题

某乎_连续问题

描述

现有某乎问答创作者信息表author_tb如下(其中author_id表示创作者编号、author_level表示创作者级别,共1-6六个级别、sex表示创作者性别):

CREATE TABLE author_tb
(
    author_id    int(10) NOT NULL,
    author_level int(10) NOT NULL,
    sex          char(10) NOT NULL
);
INSERT INTO author_tb   
VALUES 
    (101, 6, 'm'),
    (102, 1, 'f'),
    (103, 1, 'm'),
    (104, 3, 'm'),
    (105, 4, 'f'),
    (106, 2, 'f'),
    (107, 2, 'm'),
    (108, 5, 'f'),
    (109, 6, 'f'),
    (110, 5, 'm');

创作者回答情况表answer_tb如下(其中answer_date表示创作日期、author_id指创作者编号、issue_id指回答问题编号、char_len表示回答字数):

CREATE TABLE answer_tb
(
    answer_date date     NOT NULL,
    author_id   int(10) NOT NULL,
    issue_id    char(10) NOT NULL,
    char_len    int(10) NOT NULL
);

INSERT INTO answer_tb
VALUES 
    ('2021-11-1', 101, 'E001', 150),
    ('2021-11-1', 101, 'E002', 200),
    ('2021-11-1', 102, 'C003', 50),
    ('2021-11-1', 103, 'P001', 35),
    ('2021-11-1', 104, 'C003', 120),
    ('2021-11-1', 105, 'P001', 125),
    ('2021-11-1', 102, 'P002', 105),
    ('2021-11-2', 101, 'P001', 201),
    ('2021-11-2', 110, 'C002', 200),
    ('2021-11-2', 110, 'C001', 225),
    ('2021-11-2', 110, 'C002', 220),
    ('2021-11-3', 101, 'C002', 180),
    ('2021-11-4', 109, 'E003', 130),
    ('2021-11-4', 109, 'E001', 123),
    ('2021-11-5', 108, 'C001', 160),
    ('2021-11-5', 108, 'C002', 120),
    ('2021-11-5', 110, 'P001', 180),
    ('2021-11-5', 106, 'P002', 45),
    ('2021-11-5', 107, 'E003', 56);

请你统计最大连续回答问题的天数大于等于3天的用户及其等级(若有多条符合条件的数据,按author_id升序排序),以上例子的输出结果如下:
在这里插入图片描述

分析

在这里插入图片描述

实现方法

方法一(比较通用)
with t1 as (select author_id,
                   answer_date,
                   row_number() over (partition by author_id,answer_date order by answer_date) rn
            from answer_tb)
   , t2 as (select *,
                   date_sub(answer_date, interval ranking day) as days_cnt
            from (select author_id,
                         answer_date,
                         row_number() over (order by author_id) ranking
                  from t1
                  where rn = 1) table1)
   , t3 as (select author_id, count(days_cnt) days_cnt
            from t2
            group by author_id
            having count(days_cnt) >= 3)
select t3.author_id, author_level, days_cnt
from author_tb,
     t3
where author_tb.author_id = t3.author_id;
方法二(针对当前题目)
with t1 as (select *,
                   lag(answer_date) over (partition by author_id order by answer_date)  front,
                   lead(answer_date) over (partition by author_id order by answer_date) behind,
                   dense_rank() over (partition by author_id order by answer_date)      days_cnt
            from answer_tb)
select t1.author_id, author_level, days_cnt
from author_tb,
     t1
where author_tb.author_id in (select author_id
                              from t1
                              where datediff(answer_date, front) = 1
                                and datediff(behind, answer_date) = 1)
  and t1.author_id = author_tb.author_id
order by author_id,days_cnt desc
limit 1;

小结

窗口函数
时间计算函数
多表查询

某多多_连续问题

描述

两支篮球队进行了激烈的比赛,比分交替上升。比赛结束后,你有一个两队分数的明细表(名称为“分数表”)。表中记录了球队、球员号码、球员姓名、得分分数及得分时间。现在球队要对比赛中表现突出的球员进行奖励。

-- 创建分数表,并为列名增加注释
CREATE TABLE tb_score (
    team_name VARCHAR(50) COMMENT '球队名称',
    player_id INT COMMENT '球员ID',
    player_name VARCHAR(50) COMMENT '球员姓名',
    score INT COMMENT '得分',
    score_time DATETIME COMMENT '得分时间'
);
-- 插入数据以满足条件
INSERT INTO tb_score (team_name, player_id, player_name, score, score_time) VALUES
('洛杉矶湖人队', 23, '勒布朗·詹姆斯', 3, '2023-12-25 10:00:00'),
('洛杉矶湖人队', 23, '勒布朗·詹姆斯', 3, '2023-12-25 10:15:00'),
('洛杉矶湖人队', 23, '勒布朗·詹姆斯', 1, '2023-12-25 10:30:00'),
('洛杉矶湖人队', 3, '安东尼·戴维斯', 2, '2023-12-25 10:32:00'),
('洛杉矶湖人队', 23, '勒布朗·詹姆斯', 3, '2023-12-25 10:45:00'),
('洛杉矶湖人队', 23, '勒布朗·詹姆斯', 3, '2023-12-25 11:00:00'),
('洛杉矶湖人队', 23, '勒布朗·詹姆斯', 2, '2023-12-25 11:15:00'),
('洛杉矶湖人队', 23, '勒布朗·詹姆斯', 2, '2023-12-25 11:30:00'),
('金州勇士队', 30, '斯蒂芬·库里', 1, '2023-12-25 10:10:00'),
('金州勇士队', 30, '斯蒂芬·库里', 1, '2023-12-25 10:25:00'),
('金州勇士队', 30, '斯蒂芬·库里', 1, '2023-12-25 10:40:00'),
('金州勇士队', 11, '克莱·汤普森', 2, '2023-12-25 10:45:00'),
('金州勇士队', 30, '斯蒂芬·库里', 2, '2023-12-25 10:55:00'),
('金州勇士队', 30, '斯蒂芬·库里', 2, '2023-12-25 11:10:00'),
('金州勇士队', 30, '斯蒂芬·库里', 3, '2023-12-25 11:25:00'),
('金州勇士队', 30, '斯蒂芬·库里', 3, '2023-12-25 11:40:00'),
('金州勇士队', 30, '斯蒂芬·库里', 3, '2023-12-25 11:55:00');

问题:请你写一个SQL语句,统计出连续3次为球队得分的球员名单。

分析

1.本题要统计连续3次得分的球员名单,那就可以使用窗口函数,列出当前列的前一行的球员name和后一行的球员name:
前一行:lag( ) over ();后一行:lead( ) over ();
2.从第一步的临时表中,查找出球员姓名都相同的行,然后去重即为要查找的名单.

实现方法

with t1 as (select team_name,
                   player_id,
                   player_name,
                   lag(player_id) over (partition by team_name order by score_time)  front,
                   lead(player_id) over (partition by team_name order by score_time) behind
            from tb_score)
select distinct player_id, player_name, team_name
from t1
where player_id = front
  and player_id = behind;

小结

窗口函数
子查询

某团_连续问题

描述

问题 : 查询2023年每个⽉,连续2天都有登陆的⽤⼾名单.

-- todo 1 准备工作
drop database if exists db_1;

create database db_1;

use db_1;

create table tb_user_login(
    user_id varchar(32),
    login_date varchar(32)
)
;
insert into db_1.tb_user_login
values
('1', '2023-01-03'),
('1', '2023-01-04'),
('1', '2023-01-05'),
('1', '2023-01-08'),
('1', '2023-01-09'),
('1', '2023-02-16'),
('1', '2023-02-17'),
('1', '2023-02-27'),
('2', '2023-01-10'),
('2', '2023-01-11'),
('2', '2023-03-08'),
('2', '2023-03-09'),
('3', '2023-02-08'),
('3', '2023-02-09'),
('3', '2023-02-10'),
('3', '2023-02-15'),
('3', '2023-03-09'),
('3', '2023-03-19');

分析

1.去重,一天内多次登录也只算一次(看题目)
2.和拼多多的那题有一点不一样的就是这里日期列可以作为大维度的排序
3.开窗添加一列,当前行的上一行
4.比较同一行两个日期差为1即为连续登录两天.

实现方法

with t1 as (select user_id,
                   login_date,
                   lag(login_date) over (partition by user_id order by login_date) front_date
            from tb_user_login)
select distinct concat(year(login_date), '-', month(login_date)) y_month, user_id
from t1
where datediff(login_date, front_date) = 1
order by y_month;

小结

窗口函数
子查询
时间差函数:datediff()
字符串拼接函数:concat()

某鹏_连续问题

描述

每辆车连续快充最大次数.

-- 小鹏充电
drop database if exists db_1;
create database if not exists db_1;
use db_1;


CREATE TABLE charging_data (
    id VARCHAR(50),
    charge_time DATETIME,
    charge_type VARCHAR(10)
);

INSERT INTO charging_data (id, charge_time, charge_type)
VALUES
    ('XP1001', '2023-11-20 08:45:00', '快充'),
    ('XP1001', '2023-11-21 20:45:00', '快充'),
    ('XP1001', '2023-11-22 08:45:00', '快充'),
    ('XP1001', '2023-11-23 08:45:00', '慢充'),
    ('XP1001', '2023-11-25 08:45:00', '快充'),
    ('XP1002', '2023-11-25 08:45:00', '快充'),
    ('XP1002', '2023-11-25 12:45:00', '快充'),
    ('XP1002', '2023-11-25 23:45:00', '慢充'),
    ('XP1003', '2023-11-25 23:45:00', '慢充'),
    ('XP1003', '2023-11-26 23:45:00', '慢充');

需求: 汽车充电每辆车连续快充最大次数

分析

1.根据车辆排序,和根据车辆,充电类型排序
2.这两个排序相减得出一个间隔
3.统计这个次数,取最大值而且是快充类型的即可

实现方法

with t1 as (select *,
                   row_number() over (partition by id order by charge_time)             rn1,
                   row_number() over (partition by id,charge_type order by charge_time) rn2,
                   (row_number() over (partition by id order by charge_time)) -
                   (row_number() over (partition by id,charge_type order by charge_time)) diff
            from charging_data)
, t2 as (select id, diff,
                sum(if(charge_type = '快充',1,0)) cnts
         from t1
         group by id ,diff
)
select id,max(cnts) cnts
from t2
group by id;

小结

窗口函数
子查询

力扣_2173题

描述

选手的 连胜数 是指连续获胜的次数,且没有被平局或输球中断。
编写解决方案来计算每个参赛选手最多的连胜数。
结果可以以 任何顺序 返回

Create table If Not Exists Matches (player_id int, match_day date, result ENUM('Win', 'Draw', 'Lose'));
Truncate table Matches;
insert into Matches (player_id, match_day, result) values ('1', '2022-01-17', 'Win');
insert into Matches (player_id, match_day, result) values ('1', '2022-01-18', 'Win');
insert into Matches (player_id, match_day, result) values ('1', '2022-01-25', 'Win');
insert into Matches (player_id, match_day, result) values ('1', '2022-01-31', 'Draw');
insert into Matches (player_id, match_day, result) values ('1', '2022-02-08', 'Win');
insert into Matches (player_id, match_day, result) values ('2', '2022-02-06', 'Lose');
insert into Matches (player_id, match_day, result) values ('2', '2022-02-08', 'Lose');
insert into Matches (player_id, match_day, result) values ('3', '2022-03-30', 'Win');

分析

本题方法与上一题方法一致.

实现方法

with t1 as (select *,
                   row_number() over (partition by player_id order by match_day)          rn1,
                   row_number() over (partition by player_id,result order by match_day)   rn2,
                   (row_number() over (partition by player_id order by match_day)) -
                   (row_number() over (partition by player_id,result order by match_day)) diff
            from matches)
   , t2 as (select player_id,
                   diff,
                   sum(if(result = 'Win', 1, 0)) num
            from t1
            group by player_id, diff)
select player_id, max(num) longest_streak
from t2
group by player_id;

小结

窗口函数
子查询

  • 9
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值