SQL新手求助:如何用单条语句关联三张表查询歌曲及歌手信息
查询歌曲标题及对应歌手列表的SQL方案
嘿,作为SQL初学者,多表关联确实是个需要慢慢上手的知识点,不过你的场景特别典型,咱们一步步来搞定它!
首先先理清楚三张表的关联逻辑:
songs表和song_artists表通过**song_id**关联(也就是songs.id = song_artists.song_id)song_artists表和artists表通过**artist_id**关联(也就是song_artists.artist_id = artists.id)
下面分两种场景给你对应的解决方案:
1. 基础关联查询(单条记录对应单个歌手)
如果只是想看到每首歌和对应的单个歌手(一首歌有多个歌手时会显示多行),用基础的JOIN语句就可以:
SELECT s.title, a.name AS artist_name FROM songs s JOIN song_artists sa ON s.id = sa.song_id JOIN artists a ON sa.artist_id = a.id ORDER BY s.title;
针对你给出的《Memories》例子,这条语句会返回:
| title | artist_name |
|---|---|
| Memories | David Guetta |
| Memories | Kid Cudi |
2. 合并歌手列表(一行显示所有关联歌手)
如果想要把同一首歌的所有歌手合并成一个逗号分隔的列表(比如David Guetta, Kid Cudi),不同数据库有对应的聚合函数,下面是主流数据库的实现:
MySQL / MariaDB
使用 GROUP_CONCAT 函数:
SELECT s.title, GROUP_CONCAT(a.name SEPARATOR ', ') AS artist_list FROM songs s JOIN song_artists sa ON s.id = sa.song_id JOIN artists a ON sa.artist_id = a.id GROUP BY s.id, s.title ORDER BY s.title;
你的例子数据会返回:
| title | artist_list |
|---|---|
| Memories | David Guetta, Kid Cudi |
PostgreSQL
使用 STRING_AGG 函数:
SELECT s.title, STRING_AGG(a.name, ', ' ORDER BY a.name) AS artist_list FROM songs s JOIN song_artists sa ON s.id = sa.song_id JOIN artists a ON sa.artist_id = a.id GROUP BY s.id, s.title ORDER BY s.title;
SQL Server
SQL Server 2017及以上版本可以用 STRING_AGG:
SELECT s.title, STRING_AGG(a.name, ', ') AS artist_list FROM songs s JOIN song_artists sa ON s.id = sa.song_id JOIN artists a ON sa.artist_id = a.id GROUP BY s.id, s.title ORDER BY s.title;
如果是更早的版本,用 STUFF + FOR XML PATH 的组合实现:
SELECT DISTINCT s.title, STUFF(( SELECT ', ' + a.name FROM song_artists sa JOIN artists a ON sa.artist_id = a.id WHERE sa.song_id = s.id FOR XML PATH(''), TYPE ).value('.', 'NVARCHAR(MAX)'), 1, 2, '') AS artist_list FROM songs s ORDER BY s.title;
Oracle
使用 LISTAGG 函数:
SELECT s.title, LISTAGG(a.name, ', ') WITHIN GROUP (ORDER BY a.name) AS artist_list FROM songs s JOIN song_artists sa ON s.id = sa.song_id JOIN artists a ON sa.artist_id = a.id GROUP BY s.id, s.title ORDER BY s.title;
小提醒
- 上面用的是
JOIN(内连接),只会返回有对应歌手信息的歌曲;如果想包含没有录入歌手的歌曲(比如纯音乐),可以把JOIN换成LEFT JOIN。 - 分组时建议同时用
songs.id和songs.title,避免出现不同ID但标题相同的歌曲被错误合并的情况。
内容的提问来源于stack exchange,提问作者Phil90
相关产品推荐
相关产品推荐

