题解 | 每个月Top3的周杰伦歌曲
每个月Top3的周杰伦歌曲
https://www.nowcoder.com/practice/4ab6d198ea8447fe9b6a1cad1f671503
SELECT * FROM ( SELECT MONTH (a.fdate) AS month, ROW_NUMBER() OVER ( PARTITION BY MONTH (a.fdate) ORDER BY COUNT(b.song_name) DESC, a.song_id ASC ) AS ranking, b.song_name, COUNT(b.song_name) AS play_pv FROM ( SELECT fdate, user_id, song_id FROM play_log WHERE user_id IN ( SELECT user_id FROM user_info WHERE age BETWEEN 18 AND 25 ) AND YEAR (fdate) = 2022 ) a INNER JOIN ( SELECT * FROM song_info WHERE singer_name = '周杰伦' ) b ON a.song_id = b.song_id GROUP BY MONTH (a.fdate), b.song_name, a.song_id ) subquery WHERE ranking <= 3
菜鸟一枚,太久没碰sql,很多错误,题目没好好看,发现限定了歌手名字,年份,用户年龄。
简单说说自己的思路吧,这个代码是冗余了,大家看着乐就行哈哈哈。
限定条件---歌名计数---开窗函数排名(细节:开窗中要根据song_id进行升序,之前因为这个小细节报错了,题目隐含要求)
play_log表跟歌手信息表内连接而非左连接,获得能查询到的歌名(毕竟如果有播放记录,但歌名索引不到也没意义,到时候那一行歌名为空)
限定条件的实现,play_log的where里用子查询从用户信息表里获得年龄18-25之间,加上年份在2022年。内连接歌手为周杰伦的歌手信息表。至此完成限定条件,把变量整理到一个表中。
歌名计数的实现,重温了group by的使用,把count聚合的那一列之外的,需要select的列名都放在group by里,包括开窗函数中进行song_id的排名,即使没有放在select里也要group by。从而获得每月的周杰伦歌曲的播放次数
开窗函数排名:由于要根据月份分区对歌名进行排名,并且同样播放次数的排名数不同,故采用row_number() partition by月份,order by song_id asc 以及对排名进行降序。
ps:开窗函数的执行优先级等于select,在from,where,group by之后,所以要筛选前三名的,不能直接在做好开窗的表加个where就行,可以把做好排名的表作为一个子表,在子表外部进行一次where筛选。