заголовок мог бы немного сбивать с толку, позволить мне объяснить, ;) У меня есть 3 таблицы:
[names]
n_id;name
1;Jeff
2;Adam
[books]
b_id;title
1;Book1
2;Book2
[read]
n_id;b_id
Таблица [чтение] является таблицей с книгами чтения. если Adam читает "Book1", объект в [чтении] похож на это:
2;1
пока все хорошо. Теперь, есть ли способ знать, какие книги не были прочитаны человеком? Мы знаем, что только Adam прочитал книгу "Book1", таким образом, запрос должен произвести что-то вроде этого:
n_id;name;b_id;title
1;Jeff;1;Book1
1;Jeff;2;Book2
2;Adam;2;Book2
действительно ли возможно сделать это в 1 запросе, или мне нужны некоторые сценарии?
Вы можете использовать CROSS JOIN
для получения всех возможных комбинаций имен
и книг
, а затем использовать LEFT JOIN
на read
с IS NULL
для удаления существующих там строк.
При LEFT JOIN
возвращается NULL
для всех объединенных столбцов, в которых нет строк, поэтому проверка, если r.n_id IS NULL
, удаляет те строки, в которых объединение действительно нашло строки в read
.
SELECT n.n_id, n.name, b.b_id, b.title
FROM names n
CROSS JOIN books b
LEFT JOIN read r ON ( r.n_id = n.n_id AND r.b_id = b.b_id )
WHERE r.n_id IS NULL
Вы бы сделали декартово соединение между именами и книгами, чтобы получить все возможные комбинации имени / книги, а затем минус те, которые были прочитаны:
SELECT n_id, b_id
FROM names, books
MINUS
SELECT n_id, b_id
FROM read
Другие предлагали выполнить перекрестное соединение и левое соединение, что также будет работать идеально. Возможно, вы захотите попробовать оба, чтобы увидеть, что быстрее в реальном сценарии - я подозреваю, что левое соединение, предложенное другими, будет быстрее, но не совсем уверен.
Ваш вопрос был: «Есть ли способ узнать, какие книги не читал человек ?» Но результаты вашего образца запроса показали ответ на вопрос: «Есть ли способ узнать, какие книги читали не все люди?»
Если вы действительно хотите просто выполнить запрос для конкретного человека, что-нибудь вот так должно работать:
SELECT b_id, title
FROM books --You said you're just looking for books
WHERE b_id NOT IN
(SELECT b_id
FROM read
WHERE n_id = @names_id) --pass in the names_id as a parameter
Вам необходимо перекрестное соединение, чтобы сгенерировать все пары имя
vs книга
, а затем соединить с прочтите таблицу
и проверьте, где соединение не удалось.
SELECT names.n_id, names.name, books.b_id, books.title
FROM names
CROSS JOIN books
LEFT JOIN read
ON names.n_id = read.n_id AND books.b_id = read.b_id
WHERE read.n_id IS NULL