Запрос, чтобы найти, в какой строке больше всего объединений, аналогично другой строке - PullRequest
0 голосов
/ 12 апреля 2020

Мои базы данных сохраняют пользователей, песни и плейлисты, а также позволяют пользователю сохранять свои любимые песни. Я хочу помочь пользователю найти плейлисты, которые наиболее похожи на их сохраненные песни. Допустим, данные выглядят так:

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), который позволил бы мне сделать это? Принимая во внимание, что пользователь может иметь сотни сохраненных песен, и есть десятки тысяч списков воспроизведения, которые могут содержать от 1 до 500 песен. Есть ли способ написать запрос, чтобы получить эту информацию? Или лучше кэшировать этот «счет матча» в отдельной таблице (user_id, playlist_id, match_count)?

Ответы [ 2 ]

0 голосов
/ 12 апреля 2020

Вы можете использовать пару 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

Демонстрация по SQLFiddle

Обратите внимание, это даст вам плейлисты с большинством общих песен для всех пользователей. Если вам нужна информация только для одного пользователя, ответ @GordonLinoff - это путь к go.

0 голосов
/ 12 апреля 2020

Это в основном join и group 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;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...