35. Найти пользователей с взаимной подпиской
Условие задачи:
Дана таблица подписок пользователей:
user_id | follower_id
--------+------------
1 | 5
1 | 4
2 | 3
3 | 2
5 | 1
Необходимо найти пары пользователей, которые подписаны друг на друга.
Каждую пару нужно вывести только один раз.
Спойлеры к решению
Подсказки
💡 Соедини таблицу саму с собой.
💡 Для взаимной подписки должна существовать обратная запись.
💡 Условие будет выглядеть как
💡 Чтобы не получать одновременно
💡 Для взаимной подписки должна существовать обратная запись.
💡 Условие будет выглядеть как
a.user_id = b.follower_id и a.follower_id = b.user_id.💡 Чтобы не получать одновременно
(1, 5) и (5, 1), можно оставить только строки, где user_id < follower_id.Решение
Вариант через self join:
SELECT DISTINCT
f1.user_id,
f1.follower_id
FROM follows f1
JOIN follows f2
ON f1.user_id = f2.follower_id
AND f1.follower_id = f2.user_id
WHERE f1.user_id < f1.follower_id;
Для исходных данных результат будет:
user_id | follower_id
--------+------------
1 | 5
2 | 3
Условие соединения проверяет наличие обратной подписки:
f1.user_id = f2.follower_id
AND f1.follower_id = f2.user_id
Условие:
f1.user_id < f1.follower_id
оставляет каждую взаимную пару только в одном направлении.
Альтернативный вариант через EXISTS:
SELECT DISTINCT
f1.user_id,
f1.follower_id
FROM follows f1
WHERE f1.user_id < f1.follower_id
AND EXISTS (
SELECT 1
FROM follows f2
WHERE f2.user_id = f1.follower_id
AND f2.follower_id = f1.user_id
);
DISTINCT полезен, если таблица потенциально может содержать повторяющиеся записи о подписках.