【问题标题】:Query to find which row has the most joins, simliar to another row查询哪一行的连接最多,类似于另一行
【发布时间】:2020-04-12 11:15:25
【问题描述】:

我的数据库保存用户、歌曲和播放列表,并允许用户保存他们喜爱的歌曲。我想帮助用户找到与他们保存的歌曲最相似的播放列表。假设数据看起来像这样

users_saved_songs
user_id         song_id
1                    1
1                    2
1                    3
1                    4

2                    1
2                    3
2                    5
2                    7

3                    2
3                    4
3                    6
3                    8
3                    10

playlists_songs
playlist_id    song_id
1                   1
1                   5
1                   9
1                   13

2                   2
2                   6
2                   10
2                   14

3                   1
3                   2
3                   4
3                   7
3                   10
3                   13
3                   15

我想找到与用户保存的歌曲有最多共同点的播放列表。所以给定用户 ID 1,他们保存的歌曲是 [1,2,3,4]。我想根据播放列表共有多少首歌曲来订购播放列表:播放列表 1 有 1 首歌曲,播放列表 2 有 1 首歌曲,播放列表 3 有 3 首歌曲。什么是查询(我正在使用 Postgres),这将使我能够做到这个?请记住,用户可能保存了 100 首歌曲,并且有 1000 首播放列表中的 10 首,其中可能包含 1-500 首歌曲。无论如何要编写一个高性能查询来获取此信息?还是最好将“匹配分数”缓存在单独的表中(user_id、playlist_id、match_count)?

【问题讨论】:

    标签: sql postgresql


    【解决方案1】:

    这基本上是joingroup by

    select playlist_id, count)(*) as num_songs_in_common
    from playlists_songs pl join
         users_saved_songs uss
         on pl.song_id = uss.song_id
    where uss.user_id = 1
    group by playlist_id;
    

    【讨论】:

      【解决方案2】:

      您可以使用几个 CTE 来获得所需的结果,第一个计算每个用户和每个播放列表之间的重叠歌曲,第二个使用 ROW_NUMBER() 对这些计数进行降序排序,使用 playlist_id 打破平局,以及然后为每个用户选择第一行n(取决于您要返回多少个播放列表):

      WITH user_playlist_songs AS (
        SELECT u.user_id, p.playlist_id, COUNT(p.song_id) aS song_count
        FROM users_saved_songs u
        JOIN playlists_songs p ON p.song_id = u.song_id
        GROUP BY u.user_id, p.playlist_id
      ),
      song_counts AS (
        SELECT user_id, playlist_id, song_count,
               ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY song_count DESC, playlist_id) AS rn
        FROM user_playlist_songs
      )
      SELECT user_id, playlist_id, song_count
      FROM song_counts
      WHERE rn < 3
      

      输出:

      user_id     playlist_id     song_count
      1           3               3
      1           1               1
      2           1               2
      2           3               2
      3           2               3
      3           3               3
      

      Demo on SQLFiddle

      请注意,这将为您提供所有用户共有的大多数歌曲的播放列表。如果您只想要一个用户的信息,@GordonLinoff 的答案是正确的选择。

      【讨论】:

        猜你喜欢
        • 2021-09-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多