Поиск нескольких строк, которые не находятся в отношениях n: m - PullRequest
0 голосов
/ 02 октября 2018

Подобный вопрос здесь

Очень похоже на вопрос выше, но с небольшой разницей, мне нужно найти список пользователей, которые не видели хотя бы один фильм в спискеиз фильмов.

Если предположить, что две таблицы «фильмы» и «пользователи», между ними есть отношение n: m, и таблица «видимых», описывающая эти отношения.

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

Достижимо ли это в одном запросе?Я не могу найти способ сделать это.

Редактировать: Вот демонстрация с попыткой решить проблему, проблема в том, что он возвращает пользователей, которые не видели все фильмы из данногосписок.Нам нужен пользователь, который не видел ни одного фильма из этого списка: http://rextester.com/DEIH39789

Ответы [ 3 ]

0 голосов
/ 02 октября 2018

Я бы сказал что-то вроде левого присоединения таблицы пользователей к видимой таблице (и присоединения этой таблицы к таблице фильмов).

(отредактировал код из-за комментария от MatBailie)

Добавьте ограничения списка в предложении JOIN (а не в предложении WHERE, как указал мне MatBailie), и вы получите что-то вроде (код ниже должен работать на SQL-Server, но что-то подобное должно работать дляMySql также):

SELECT COUNT(Users.ID)
FROM Users
LEFT JOIN Seen ON Users.ID = Seen.UserID AND Users.something IN (list)
LEFT JOIN Movies ON Seen.MovieID = Movie.ID AND Movies.something IN (list)
WHERE Movies.ID IS NULL
GROUP BY User.ID -- <-- This is probably optional

Но так как обычно есть несколько способов получить один и тот же результат, скорректированная версия моего предыдущего ответа:

SELECT COUNT(Users.ID)
FROM Users
LEFT JOIN Seen ON Users.ID = Seen.UserID
LEFT JOIN Movies ON Seen.MovieID = Movie.ID
WHERE (Users.something IN (list) OR Users.something IS NULL)
  AND (Movies.something IN (list) OR Movies.something IS NULL)
  AND Movies.ID IS NULL
GROUP BY User.ID -- <-- This is probably optional

Третья попытка: получить всех пользователей-идс в списке, которые видели один из фильмов.Затем, получите все идентификаторы в списке и вычтите идентификаторы, которые видели один из этих фильмов.Знайте, что для больших наборов данных (пара тысяч невелика) этот запрос может стать медленным.Чтобы проверить это, я удалил «userid = 2 и movieid = 3» из списка увиденных, иначе я не получил бы результат.Теперь я вижу, что Ник не видел ни одного из первых трех фильмов (ссылаясь на ваш пример rextester)

SELECT *
FROM musers
WHERE musers.id IN (1,2,3)
  AND musers.id NOT IN (
    SELECT musers.id
    FROM musers
    JOIN Seen ON musers.ID = Seen.UserID 
    JOIN Movies ON Seen.MovieID = movies.ID 
    WHERE movies.id IN (1,2,3) )
0 голосов
/ 02 октября 2018

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

users (id int, name varchar(20));
movies (id int, title varchar(20));
seen (user_id int, movie_id int);

SELECT u.*
FROM users u
LEFT JOIN seen s
ON s.user_id = u.id AND s.movie_id IN (movielist)
WHERE s.user_id IS NULL AND u.id IN (userlist)

Условие WHERE s.user_id IS NULL означает, что LEFT JOIN дает вам всех пользователей, которые не видели ни одного фильмов в movielist, а u.id IN (userlist) затем ограничивает результаты только этим набором пользователей.Вы бы изменили условия IN, чтобы они соответствовали списку фильмов и пользователей, которых вы интересовали. Я сделал небольшую демонстрацию для Rextester .

Обновление

Я неправильно понял вопрос;желаемый результат для пользователей, которые не видели ни одного (или нескольких) фильмов в списке.Этот запрос решает эту проблему:

SELECT u.*
FROM musers u
LEFT JOIN seen s
ON s.user_id = u.id AND s.movie_id IN (1, 2)
WHERE u.id IN (1, 2, 3)
GROUP BY u.id
HAVING COUNT(s.movie_id) < 2

Результатом JOIN и WHERE являются пользователи (1, 2, 3) и фильмы, которые они видели.Если они видели все фильмы в списке фильмов (1, 2), COUNT фильмов в seen будет равно 2, в противном случае, если они не видели один (или более), он будет меньше 2. Вот обновленная демоверсия .Обратите внимание, что при изменении длины списка фильмов 2 в предложении HAVING должно измениться, чтобы соответствовать длине списка фильмов.

0 голосов
/ 02 октября 2018

с учетом отношения: m между пользователями и таблицей Movies с промежуточной таблицей Seen.

SELECT * FROM Users u WHERE NOT EXISTS (SELECT UserId FROM Seen s WHERE s.UserId = u.ID)

этот запрос вернет пользователей, у которых нет связанных записей в таблице Seen

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...