某乎_连续问题
描述
现有某乎问答创作者信息表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;
小结
窗口函数
子查询