MySQL查询返回全量歌曲并标识用户是否已拥有该歌曲
解决SELECT查询中返回存在标识字段且避免重复的问题
你的问题很典型——当关联用户歌曲表来添加hasSong标识时,原本的去重逻辑失效了,本质原因是hasSong的存在让原本相同的歌曲行产生了差异,DISTINCT无法再合并它们。下面给你两种可靠的解决方案:
方法一:LEFT JOIN + GROUP BY(适合需扩展获取关联表字段的场景)
通过左关联用户歌曲表,再按歌曲的唯一信息分组,用聚合函数判断是否存在匹配记录:
SELECT song.id AS id_song, CONCAT(song.article, ' ', song.name) AS name, -- 用COUNT判断是否有匹配的用户歌曲记录,返回1或0 CASE WHEN COUNT(user_song.id) > 0 THEN 1 ELSE 0 END AS hasSong FROM song -- 关联时直接限定用户ID,避免无关记录干扰 LEFT JOIN user_song ON song.id = user_song.song_id AND user_song.user_id = 123 -- 替换为你的目标用户ID WHERE song.source = '指定来源' -- 替换为你的目标来源 -- 按歌曲的唯一标识分组,确保每个歌曲只返回一行 GROUP BY song.id, song.article, song.name;
这种方式的好处是,如果后续需要从user_song表获取其他字段(比如收藏时间),可以直接在SELECT里添加对应的聚合函数(比如MAX(user_song.created_at))。
方法二:EXISTS子查询(简洁高效,仅判断存在性)
如果只需要判断用户是否拥有该歌曲,用EXISTS子查询会更直接,而且性能通常更好(因为子查询找到匹配项就会停止检索):
SELECT song.id AS id_song, CONCAT(song.article, ' ', song.name) AS name, -- EXISTS返回布尔值,数据库通常会转为1(存在)或0(不存在) EXISTS ( SELECT 1 FROM user_song WHERE user_song.song_id = song.id AND user_song.user_id = 123 -- 替换为你的目标用户ID ) AS hasSong FROM song WHERE song.source = '指定来源'; -- 替换为你的目标来源
这种写法不需要分组,逻辑更清晰,每个歌曲必然只返回一行,完全不会出现重复问题。
小提示
记得把SQL里的123和'指定来源'替换为你实际的用户ID和来源值。另外如果使用MySQL,要确保你的GROUP BY语句符合ONLY_FULL_GROUP_BY模式的要求(也就是所有非聚合字段都要出现在GROUP BY里)。
内容的提问来源于stack exchange,提问作者Renan Aguiar
相关产品推荐
相关产品推荐

