首页 > 试题广场 >

每个月Top3的周杰伦歌曲

[编程题]每个月Top3的周杰伦歌曲
  • 热度指数:242598 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
从听歌流水中找到18-25岁用户在2022年每个月播放次数top 3的周杰伦的歌曲。

流水表 play_log:
日期 (fdate) 用户 ID (user_id) 歌曲 ID (song_id)
2022-01-08 10000 0
2022-01-16 10000 0
2022-01-20 10000 0
2022-01-25 10000 0
2022-01-02 10000 1
2022-01-12 10000 1
2022-01-13 10000 1
2022-01-14 10000 1
2022-01-10 10000 2
2022-01-11 10000 3
2022-01-16 10000 3
2022-01-11 10000 4
2022-01-27 10000 4
2022-02-05 10000 0
2022-02-19 10000 0
2022-02-07 10000 1
2022-02-27 10000 2
2022-02-25 10000 3
2022-02-03 10000 4
2022-02-16 10000 4
歌曲表song_info
歌曲 ID (song_id) 歌曲名称 (song_name) 歌手名称 (singer_name)
0 明明就 周杰伦
1 说好的幸福呢 周杰伦
2 江南 林俊杰
3 大笨钟 周杰伦
4 黑键 林俊杰
用户表user_info
user_id age
10000 18
输出:
month ranking song_name play_pv
1 1 明明就 4
1 2 说好的幸福呢 4
1 3 大笨钟 2
2 1 明明就 2
2 2 说好的幸福呢 1
2 3 大笨钟 1

示例1

输入

drop table if exists play_log;
create table `play_log` (
    `fdate` date,
    `user_id` int,
    `song_id` int
);
insert into play_log(fdate, user_id, song_id)
values 
('2022-01-08', 10000, 0),
('2022-01-16', 10000, 0),
('2022-01-20', 10000, 0),
('2022-01-25', 10000, 0),
('2022-01-02', 10000, 1),
('2022-01-12', 10000, 1),
('2022-01-13', 10000, 1),
('2022-01-14', 10000, 1),
('2022-01-10', 10000, 2),
('2022-01-11', 10000, 3),
('2022-01-16', 10000, 3),
('2022-01-11', 10000, 4),
('2022-01-27', 10000, 4),
('2022-02-05', 10000, 0),
('2022-02-19', 10000, 0),
('2022-02-07', 10000, 1),
('2022-02-27', 10000, 2),
('2022-02-25', 10000, 3),
('2022-02-03', 10000, 4),
('2022-02-16', 10000, 4);

drop table if exists song_info;
create table `song_info` (
    `song_id` int,
    `song_name` varchar(255),
    `singer_name` varchar(255)
);
insert into song_info(song_id, song_name, singer_name) 
values
(0, '明明就', '周杰伦'),
(1, '说好的幸福呢', '周杰伦'),
(2, '江南', '林俊杰'),
(3, '大笨钟', '周杰伦'),
(4, '黑键', '林俊杰');

drop table if exists user_info;
create table `user_info` (
    `user_id`   int,
    `age`       int
);
insert into user_info(user_id, age) 
values
(10000, 18)

输出

month|ranking|song_name|play_pv
1|1|明明就|4
1|2|说好的幸福呢|4
1|3|大笨钟|2
2|1|明明就|2
2|2|说好的幸福呢|1
2|3|大笨钟|1

说明

1月被18-25岁用户播放次数最高的三首歌为“明明就”、“说好的幸福呢”、“大笨钟”,“明明就”和“说好的幸福呢”播放次数相同,排名先后由两者的song_id先后顺序决定。2月同理。



备注:
MySQL中,日期转月份的函数为 month(),例:SELECT MONTH(‘2016-01-16') 返回 1。
SELECT month,ranking,song_name,play_pv
FROM(
SELECT MONTH(t.fdate) AS month,
t1.song_name AS song_name,
COUNT(*) AS play_pv,
ROW_NUMBER() OVER (PARTITION BY MONTH(t.fdate) ORDER BY COUNT(*) DESC,t1.song_id ASC ) AS ranking
FROM play_log AS t INNER JOIN song_info t1 ON t.song_id=t1.song_id
INNER JOIN user_info t2 ON t.user_id=t2.user_id
WHERE t2.age BETWEEN 18 AND 25 AND year(fdate)=2022 AND t1.singer_name='周杰伦'
GROUP BY month,t1.song_name,t1.song_id
) AS temp
WHERE temp.ranking<=3
ORDER BY month, ranking

发表于 2026-03-25 13:21:38 回复(0)
# 限定排名为前3
select *
from(
# 增添排名信息
select month,row_number() over(partition by month order by play_pv desc) as ranking,song_name,play_pv
from(
# 提取月度信息并按照月度、歌曲名分组计算播放量
select month(fdate) as month,song_id,song_name,count(*) as play_pv
from(
# 整合所有表信息并筛选满足条件的内容
select p.fdate,p.user_id,p.song_id,s.song_name,s.singer_name,u.age
from play_log as p
left join song_info as s on p.song_id = s.song_id
left join user_info as u on p.user_id = u.user_id
where p.fdate like "2022%" and s.singer_name = "周杰伦" and u.age >=18 and u.age<=25
) as temp
group by month(fdate),song_id,song_name
order by month(fdate) asc,song_id asc
) as temp2
) as temp3
where ranking<=3

发表于 2026-03-21 18:48:28 回复(0)
song_id
发表于 2026-03-14 20:01:45 回复(0)
with
month_info as
(select month(fdate) month, p.user_id, s.song_id, song_name from play_log p
join song_info s on p.song_id = s.song_id
join user_info u on p.user_id = u.user_id
where age between 18 and 25
and singer_name = '周杰伦'
and year(fdate) = 2022
),

play_pv_info as
(select month, song_name, song_id, count(*) as play_pv
from month_info
group by month, song_id, song_name),

rank_info as
(select month,
row_number()over(partition by month order by play_pv desc, song_id) ranking,
song_id,
song_name,
play_pv
from play_pv_info)

select month, ranking, song_name, play_pv
from rank_info
where ranking <= 3
order by month, ranking

发表于 2026-02-07 04:25:11 回复(1)
题目有问题 不说清楚排序
发表于 2026-01-30 14:51:43 回复(0)
select sub.month ,sub.ranking ,sub.song_name,sub.play_pv
from (
select month(p.fdate) as month,s.song_name as song_name,count(*) as play_pv,
row_number() over(partition by month(p.fdate) order by count(*) desc) as ranking
from play_log p
join song_info s on p.song_id = s.song_id
join user_info u on p.user_id = u.user_id
where s.singer_name = '周杰伦' and
year(p.fdate) = "2022" and
u.age between 18 and 25
group by month,s.song_name
) as sub
where sub.ranking < 4
这道就是条件比较多,需要注意的是非聚合字段与分组维度的问题

发表于 2026-01-28 16:57:13 回复(0)
难点一个窗口函数分组排序
row_number() over (
                partition by
                    month(fdate)
                order by
                    count(p.song_id) desc,
                    s.song_id
            ) as ranking

发表于 2025-12-26 15:05:07 回复(0)
select xx.month,	xx.ranking,	xx.song_name,	xx.play_pv
from (

select
    x.month,
    
    row_number() over (
        partition by
            x.month
        order by
            x.play_pv desc,
            x.song_id asc
    ) as ranking,
    x.song_name,
    x.play_pv
from
    (
        select
            month(a.fdate) as month,
            b.song_name,
            count(a.song_id) as play_pv,
            a.song_id
        from
            play_log a
            left join song_info b on a.song_id = b.song_id
            left join user_info c on a.user_id = c.user_id
        where
            b.singer_name = "周杰伦" and
            c.age >= 18 and c.age <= 25  and year(a.fdate) = 2022
        group by
            month,
            song_name,
            song_id
    ) x ) xx
where ranking <= 3

发表于 2025-11-27 02:15:20 回复(0)
SELECT c.month, row_number() over(partition by c.month order by c.play_pv desc) as ranking,c.song_name,c.play_pv
from
(select  substr(fdate,7,1) as month, song_name, song_id,count(*) as play_pv
from
(select a.*,b.age,c.song_name,c.singer_name  from play_log  a
left join user_info b on a.user_id=b.user_id
left join song_info c  on a.song_id=c.song_id  where singer_name='周杰伦' and substr(fdate,1,4)='2022' and age between 18 and 25) a group by substr(fdate,7,1),song_name,song_id
) c


这样写点击“”自测运行”的时候 是和结果输出一致的,但是点击“保存并提交”的时候有问题,是什么原因

发表于 2025-11-17 15:54:15 回复(0)
数量相同的时候要按照song_id升序排列,可能这就是考题和业务的差别
select
    *
from
    (
        select
            month(fdate) month,
            row_number() over (
                partition by
                    month(fdate)
                order by
                    count(*) desc,p.song_id asc
            ) ranking,
            song_name,
            count(*) play_pv
        from
            play_log p
            join song_info s on s.song_id = p.song_id
            and s.singer_name = '周杰伦'
            and year(p.fdate) = '2022'
            join user_info u on u.user_id = p.user_id
            and u.age between 18 and 25
            
        group by
            month,
            s.song_name,
            s.song_id
    ) count_info
where
    count_info.ranking <= 3


发表于 2025-11-16 11:14:13 回复(0)
如果提交报错,可能是因为存在排名听歌数量相同但是排名不一样的歌曲,因此需要在窗口函数的orderby部分按照song_id再升序排列即可.
发表于 2025-11-13 17:35:46 回复(0)
with t1 as (
select month(fdate) as month,x.user_id,song_id
from user_info x 
join play_log y 
using(user_id)
where year(fdate)=2022 and (age between 18 and 25)
),t2 as (
select t1.month,t1.song_id,song_name,count(song_id) as play_pv
from t1 
join song_info 
using(song_id)
where singer_name='周杰伦'
group by 1,2,3
)
select month,ranking,song_name,play_pv
from
(select month,song_id,song_name,play_pv,
row_number() over(partition by month order by play_pv desc,song_id) as ranking
from t2) e
where ranking<=3
order by 1,2

发表于 2025-10-16 11:22:19 回复(0)
with t as( select
            month(fdate) as month,
            song_id,
            count(song_id) as play_pv
        from
            play_log
            where user_id in
            (select
            user_id
            from user_info
            where age between 18 and 25)
        group by
            month(fdate),
            song_id)
select
    *
    from (select
        t.month, row_number() over (partition by t.month order by t.play_pv desc) as ranking,a.song_name,t.play_pv
from t join
(select
    *
    from song_info
    where singer_name="周杰伦") a
    on t.song_id=a.song_id) b
    where b.ranking<=3  
反思:有筛选字段在需要join的表里面,需要先join之后在进行row_number的排序
发表于 2025-10-06 20:19:07 回复(0)
窗口函数row_number()中要写t3.song_id asc,是因为在这个 SQL 查询中,row_number()函数里使用t3.song_id asc作为排序条件的一部分,主要是为了处理计数相同的情况,确保排序结果的唯一性和确定性。
select
    *
from(
    select 
        month(t1.fdate) as month
        ,row_number() over(partition by month(t1.fdate) order by count(1) desc,t3.song_id asc) as ranking
        ,t3.song_name
        ,count(1) as play_pv
    from play_log as t1
        left join user_info as t2 on t1.user_id = t2.user_id
        left join song_info as t3 on t1.song_id = t3.song_id
    where year(t1.fdate) = 2022
        and t2.age between 18 and 25
        and t3.singer_name = '周杰伦' 
    group by MONTH(t1.fdate),t1.song_id,t3.song_name
)t1 
where ranking <=3
order by month,ranking


发表于 2025-09-16 16:32:33 回复(0)
求助,代码通过自测运行但是提交没有通过,不知道哪里出了问题,求大神解答
select * from (select month,row_number()over(partition by month order by count(song_name) desc) as ranking,song_name, count(song_name) as play_pv  from (select year(fdate) as Y,month(fdate) as month,song_name,singer_name,age from play_log left join song_info on play_log.song_id=song_info.song_id left join user_info on play_log.user_id=user_info.user_id  where singer_name="周杰伦" and age between 18 and 25 ) as new where Y=2022  group by month,song_name ) as up where ranking<=3 order by month,ranking 
发表于 2025-09-11 16:14:45 回复(0)
小白不解 song_name和p.song_id不是一一对应的吗 为什么还要同时group by
发表于 2025-09-10 20:16:36 回复(2)
Select
    t.month
    ,t.ranking
    ,t.song_name
    ,t.play_pv
from
    (Select
        b.song_name
        ,month(a.fdate) as month
        ,count(*) as play_pv
        ,row_number () over (
            partition by month(a.fdate)
            order by count(*) desc, b.song_id asc
        ) as ranking
    from play_log a
    inner join user_info c on a.user_id = c.user_id
    inner join song_info b on a.song_id = b.song_id
    where b.singer_name = "周杰伦"
    and c.age between 18 and 25
    group by b.song_name, month(a.fdate),b.song_id
    )t
where t.ranking <= 3
order by t.month asc, t.ranking asc;
发表于 2025-09-01 21:20:57 回复(0)
select
    month,
    ranking,
    song_name,
    play_pv
from
    (
        select
            month(pl.fdate) as month,
            si.song_name,
            si.song_id,
            count(*) as play_pv,
            row_number() over (
                partition by
                    month(pl.fdate)
                order by
                    count(*) desc,si.song_id
            ) as ranking
        from
            play_log pl
            left join song_info si on pl.song_id = si.song_id
            left join user_info ui on pl.user_id = ui.user_id
        where
            si.singer_name = '周杰伦'
            and ui.age between 18 and 25
            and year(pl.fdate) = 2022
        group by month(pl.fdate),si.song_name,si.song_id
    ) as song_log
where
    ranking <= 3
order by
    month,ranking;

发表于 2025-08-17 00:50:56 回复(0)
row_number排序,数量相同的时候,序号就是随机的,这种答案还能判为错吗?

发表于 2025-08-08 10:50:38 回复(0)