MariaDB 10.1.29单查询获取Top3热门歌曲+3首非热门随机歌曲
解决方案:合并最受欢迎歌曲与随机歌曲
针对你的MariaDB 10.1.29版本限制,我们可以通过用户变量排名结合UNION ALL来实现需求,既规避子查询LIMIT的问题,又能精确获取两组目标数据:
( -- 第一部分:3首最受欢迎的歌曲(按liked降序取前3) SELECT song_id, name, liked FROM ( SELECT song_id, name, liked, @rank := @rank + 1 AS rank FROM song, (SELECT @rank := 0) AS init_rank ORDER BY liked DESC ) AS ranked_songs WHERE rank <= 3 ) UNION ALL ( -- 第二部分:3首不在前3范围内的随机歌曲 SELECT song_id, name, liked FROM ( SELECT song_id, name, liked, @rank2 := @rank2 + 1 AS rank FROM song, (SELECT @rank2 := 0) AS init_rank2 ORDER BY liked DESC ) AS ranked_songs WHERE rank > 3 ORDER BY RAND() LIMIT 3 ) ORDER BY -- 可选:让结果先显示最受欢迎组,再显示随机组 CASE WHEN rank <=3 THEN 1 ELSE 2 END;
为什么你的尝试语句无效?
我们来拆解你遇到的核心问题:
第一个查询的问题:
你用笛卡尔积关联主表和前3歌曲的子查询,这会导致非前3的歌曲与前3的每一行都匹配,产生大量重复行。最后LIMIT 3拿到的可能是重复数据,逻辑完全偏离需求。正确的思路应该是拆分两组数据分别查询,再合并结果。第二个查询的问题:
NOT IN(b.ids)中的b.ids是一个逗号分隔的字符串(比如"6,8,5"),而NOT IN需要的是独立值列表。数据库会把整个字符串当作单个值去匹配,自然找不到符合条件的歌曲。你可以改用FIND_IN_SET(a.song_id, b.ids) = 0来检查song_id是否不在这个字符串里,但这种方式不如变量排名可靠(比如GROUP_CONCAT有长度限制)。
额外说明
- 如果你的
song_id是主键,变量排名的方式可以确保精确取到前3首最受欢迎的歌曲,即使存在liked值并列的情况。 ORDER BY RAND()在数据量较大时性能会下降,但如果你的表数据量不大,这个写法完全够用。
内容的提问来源于stack exchange,提问作者Kien Pham
相关产品推荐
相关产品推荐

