MySQL:按名称与艺人分组合并Spotify重复曲目
解决Spotify多版本曲目合并的数据库策略
嘿,刚帮几个做音乐数据清洗的朋友解决过几乎一模一样的Spotify多版本曲目合并问题,咱们从核心逻辑到具体SQL一步步来拆解:
核心判定逻辑梳理
首先得明确哪些情况属于“同一首歌的不同版本”:
- 单艺人场景:就像你提到的蕾哈娜《Love On The Brain》的6条记录,核心判定依据是标准化后的曲目名称 + 主艺人ID——同一首歌的不同发行版本,主艺人ID固定,曲目名可能带版本后缀(比如
(US Version)、(Explicit)),去掉后缀后就能精准匹配。 - 多合作艺人场景:难度确实会上升,这时候要抓核心艺人组——把所有主艺人的ID排序后拼接成固定字符串,再加上标准化曲目名。毕竟合作歌曲的艺人顺序可能在不同版本里调换(比如
Artist A & Artist B和Artist B & Artist A),排序后就能统一判定标准。 - 终极权威依据:Spotify曲目的
isrc字段(国际标准录音代码)是同一录音的唯一标识,只要ISRC相同,百分百是同一首歌的不同发行版本,优先级高于名称+艺人ID。
1. 单艺人曲目合并实操(SQL示例)
假设你的三张关联表结构如下(结合Spotify常见字段补充):
Tracks:track_id,track_name,duration_ms,release_date,isrcArtists:artist_id,artist_nameTrack_Artists:track_id,artist_id,role(区分主艺人main、客串featured等)
先标准化曲目名,再分组找出重复项,最后生成合并建议:
-- 第一步:标准化曲目名称,移除末尾的版本后缀(比如(US Version)、(Explicit)) WITH standardized_tracks AS ( SELECT track_id, REGEXP_REPLACE(track_name, '\s*\(.*?\)$', '') AS standardized_name, duration_ms, isrc, release_date FROM Tracks ), -- 第二步:通过「主艺人ID + 标准化曲目名」分组,筛选出重复记录 track_duplicates AS ( SELECT st.standardized_name, ta.artist_id AS main_artist_id, ARRAY_AGG(st.track_id) AS duplicate_track_ids, MIN(st.release_date) AS earliest_release, MAX(st.release_date) AS latest_release FROM standardized_tracks st JOIN Track_Artists ta ON st.track_id = ta.track_id WHERE ta.role = 'main' -- 只取主艺人,排除客串、制作人等 GROUP BY st.standardized_name, ta.artist_id HAVING COUNT(st.track_id) > 1 ) -- 第三步:生成合并建议,可选择保留最早/最新发行版本 SELECT standardized_name AS track_name, a.artist_name AS main_artist, duplicate_track_ids, earliest_release, latest_release, -- 这里选择保留最早发行的版本,可按需修改 (SELECT track_id FROM standardized_tracks st WHERE st.standardized_name = td.standardized_name AND st.release_date = td.earliest_release LIMIT 1) AS keep_track_id FROM track_duplicates td JOIN Artists a ON td.main_artist_id = a.artist_id;
2. 多合作艺人的合并难点破解
针对多主艺人的歌曲,关键是统一艺人顺序的判定标准,再结合ISRC做权威验证:
WITH standardized_tracks AS ( SELECT track_id, REGEXP_REPLACE(track_name, '\s*\(.*?\)$', '') AS standardized_name, isrc FROM Tracks ), -- 获取每个曲目的主艺人ID,排序后拼接成固定字符串(避免艺人顺序干扰) track_main_artists AS ( SELECT track_id, STRING_AGG(artist_id ORDER BY artist_id) AS main_artist_ids_sorted FROM Track_Artists WHERE role = 'main' GROUP BY track_id ), -- 按「标准化曲目名 + 排序后主艺人ID」分组,筛选重复项 multi_artist_duplicates AS ( SELECT st.standardized_name, tma.main_artist_ids_sorted, ARRAY_AGG(st.track_id) AS duplicate_track_ids, ARRAY_AGG(DISTINCT st.isrc) AS isrc_list FROM standardized_tracks st JOIN track_main_artists tma ON st.track_id = tma.track_id GROUP BY st.standardized_name, tma.main_artist_ids_sorted HAVING COUNT(st.track_id) > 1 ) -- 生成合并建议,优先用ISRC判定 SELECT standardized_name AS track_name, -- 把排序后的艺人ID转换为艺人名称 (SELECT STRING_AGG(artist_name ORDER BY artist_id) FROM Artists WHERE artist_id IN (STRING_TO_ARRAY(tma.main_artist_ids_sorted, ','))) AS main_artists, duplicate_track_ids, isrc_list, -- 若ISRC统一,保留对应版本;否则保留第一个出现的版本 CASE WHEN array_length(isrc_list, 1) = 1 THEN (SELECT track_id FROM standardized_tracks st WHERE st.isrc = (SELECT unnest(isrc_list) LIMIT 1) LIMIT 1) ELSE (SELECT track_id FROM standardized_tracks st WHERE st.track_id = (SELECT unnest(duplicate_track_ids) LIMIT 1)) END AS keep_track_id FROM multi_artist_duplicates tma;
3. 关联表的同步更新
合并Tracks表后,别忘了同步更新Track_Artists等关联表,把重复记录的关联指向保留的track_id:
-- 先创建合并映射表(从前面的查询结果导出) WITH merge_map AS ( SELECT unnest(duplicate_track_ids) AS old_track_id, keep_track_id AS new_track_id FROM track_duplicates -- 可同时包含multi_artist_duplicates的结果 ) -- 更新Track_Artists表,替换旧track_id为新的 UPDATE Track_Artists ta SET track_id = mm.new_track_id FROM merge_map mm WHERE ta.track_id = mm.old_track_id; -- 最后删除重复的Tracks记录(⚠️执行前务必备份数据!) DELETE FROM Tracks WHERE track_id IN (SELECT old_track_id FROM merge_map);
内容的提问来源于stack exchange,提问作者Ealau
相关产品推荐
相关产品推荐

