如何使用SQL实现艺术家歌曲统计及特征歌曲查询?是否需要使用子查询?
解决你的SQL查询需求:获取艺术家的歌曲统计及特色歌曲
嘿,我来帮你搞定这个SQL查询问题!你的需求是从lt.artist表中提取每个艺术家的歌曲数量,以及他们在流行度、声学特性、能量感三个维度上的代表性歌曲,当前的查询确实没法满足需求,我来给你拆解问题并提供两种可行的方案。
先说说你当前代码的问题
你的原查询:
SELECT artists AS artist, count(name) AS songs, name , acousticness, energy , popularity FROM lt.artist GROUP BY artists ORDER BY popularity DESC, acousticness DESC, energy DESC
这里有两个核心问题:
- GROUP BY 后的字段不匹配:按照SQL标准,SELECT列表里的非聚合字段(比如
name、acousticness)必须出现在GROUP BY里,否则数据库要么报错(开启严格模式时),要么返回随机值,这显然不是你想要的对应维度的top歌曲。 - 没有按艺术家分组筛选维度top1:你只是做了全局排序,没法针对每个艺术家单独找出他们的最高流行度、最高声学特性的歌曲。
方案一:用窗口函数(推荐,高效清晰)
如果你的数据库支持窗口函数(比如MySQL 8.0+、PostgreSQL、SQL Server等),这是最优解,只需要扫描一次表就能完成所有计算:
WITH ranked_songs AS ( SELECT artist, name AS song_name, acousticness, energy, popularity, -- 给每个艺术家的歌曲按流行度降序排名,行号1就是最流行的 ROW_NUMBER() OVER (PARTITION BY artist ORDER BY popularity DESC) AS rn_pop, -- 按声学特性降序排名 ROW_NUMBER() OVER (PARTITION BY artist ORDER BY acousticness DESC) AS rn_acoustic, -- 按能量值降序排名 ROW_NUMBER() OVER (PARTITION BY artist ORDER BY energy DESC) AS rn_energy FROM lt.artist ) SELECT artist, COUNT(DISTINCT song_name) AS song_count, -- 如果歌曲不会重复,用COUNT(*)也可以 MAX(CASE WHEN rn_pop = 1 THEN song_name END) AS most_popular_song, MAX(CASE WHEN rn_acoustic = 1 THEN song_name END) AS most_acoustic_song, MAX(CASE WHEN rn_energy = 1 THEN song_name END) AS most_energised_artist_song FROM ranked_songs GROUP BY artist ORDER BY artist;
代码解释
- 首先用CTE(
ranked_songs)给每个艺术家的每首歌做三个维度的排名,PARTITION BY artist确保排名是在每个艺术家的范围内进行的。 - 主查询里,用
COUNT统计每个艺术家的歌曲总数,再通过CASE配合MAX函数,把每个维度排名第一的歌曲名提取出来。
如果遇到同一维度有并列第一的歌曲(比如两首歌流行度相同),可以把ROW_NUMBER()换成RANK()或者DENSE_RANK(),这样并列的歌曲都会被标记为行号1,后续可以根据需求调整如何展示(比如用GROUP_CONCAT把并列歌曲拼起来)。
方案二:用子查询(兼容老版本数据库)
如果你的数据库不支持窗口函数(比如MySQL 5.7及更早版本),可以用子查询的方式实现,逻辑更直观:
SELECT a.artist, COUNT(*) AS song_count, -- 子查询获取当前艺术家最流行的歌曲 (SELECT name FROM lt.artist a2 WHERE a2.artist = a.artist ORDER BY popularity DESC LIMIT 1) AS most_popular_song, -- 子查询获取当前艺术家最具声学特性的歌曲 (SELECT name FROM lt.artist a2 WHERE a2.artist = a.artist ORDER BY acousticness DESC LIMIT 1) AS most_acoustic_song, -- 子查询获取当前艺术家最具能量感的歌曲 (SELECT name FROM lt.artist a2 WHERE a2.artist = a.artist ORDER BY energy DESC LIMIT 1) AS most_energised_artist_song FROM lt.artist a GROUP BY a.artist ORDER BY a.artist;
代码解释
每个子查询都针对当前艺术家,按指定维度降序排序后取第一首歌的名称,主查询负责统计每个艺术家的歌曲总数。不过这种方法在数据量大的时候性能会差一些,因为每个子查询都会单独扫描一次表。
最终效果
这两种方案都能输出你想要的格式:
| artist | song_count | most_popular_song | most_acoustic_song | most_energised_artist_song |
|---|---|---|---|---|
| Justin Timberlake | 150 | Mirrors | Cry Me A River | Can’t Stop The Feeling |
内容的提问来源于stack exchange,提问作者user16623889




