#sqlite #join
#sqlite #Присоединиться
Вопрос:
здесь немного длинный снимок с немного запутанным
У меня есть следующие 4 запроса, которые при выполнении по порядку выдают 104 строки. Последовательность выглядит следующим образом;
select *
from borrow
where personid = 14
ищу transactionid здесь — возвращает 791 и 1314
select *
from borrow_copy
where transactionid IN (791, 1314)
Ищу здесь bookdescid — возвращает 126 и 110
select *
from book
where bookdescid IN (126, 110)
Ищу subjectid здесь — возвращает 12 11
select *
from book
where subjectid IN (12,11)
Ищу все книги с subjectid 12 и 11 здесь. Возвращает количество строк 104
Я в основном пытаюсь объединить все эти шаги, описанные выше, в один запрос, который в конечном итоге возвращает заголовок и подзаголовок всех книг, которые имеют subjectid 12 или 11. Я попытался сделать это в приведенном ниже запросе, который продемонстрирует, какие столбцы есть в каждой таблице, но, похоже, я не могу его завершить
Я полагаю, что приведенный ниже запрос завершает шаг 2 в последовательности, поскольку он возвращает правильные 2 книги, которые затем идентифицируют subjectid, необходимые в конечных результатах, как 12 и 11
SELECT title, subtitle
FROM book
JOIN book_copy ON book.bookdescid = book_copy.bookdescid
JOIN borrow_copy ON book_copy.bookid = borrow_copy.bookid
JOIN borrow ON borrow_copy.transactionid = borrow.transactionid
JOIN person ON borrow.personid = person.personid
WHERE borrow_copy.transactionid IN(
SELECT borrow_copy.transactionid
FROM borrow_copy
WHERE borrow.personid = 14)
По сути, я застрял на этом этапе, поскольку я не уверен, как сказать, что из 2 записей, возвращенных из приведенного выше запроса, используйте столбец subjectid, чтобы теперь вернуть мне все заголовок и подзаголовок из таблицы book, где subjectid тот же
Шаг 1:
Шаг 2:
Шаг 3:
Шаг 4:
SELECT
title,
subtitle
FROM
book
JOIN book_copy ON book.bookdescid = book_copy.bookdescid
JOIN borrow_copy ON book_copy.bookid = borrow_copy.bookid
JOIN borrow ON borrow_copy.transactionid = borrow.transactionid
JOIN person ON borrow.personid = person.personid
WHERE
borrow_copy.transactionid IN
(
SELECT
borrow_copy.transactionid
FROM
borrow_copy
WHERE
borrow.personid = 14 IN
(
SELECT
NULL
FROM
book
WHERE
book.bookdescid IN
(
SELECT
NULL
FROM
book
WHERE
book.subjectid = book.subjectid
)
)
);
Комментарии:
1. Шаг 1 — prnt.sc/vffu0d Шаг 2 — prnt.sc/vffu8r Шаг 3 — prnt.sc/vffuf0 Шаг 4 — (заключительный) prnt.sc/vffukp
2. Избегайте использования
WHERE x IN ( SELECT y FROM z )
для фильтрации результатов, когда вы уже объединяете одни и те же таблицы — вы в конечном итоге запутаетесь.3. Вы говорите, что хотите использовать только
title
иsubtitle
изbook
таблицы, основанной на теме книги — так почему вы используетеborrow
иborrow_copy
иbook_copy
— как они относятся к запросу? Почему вы ссылаетесь на них?4. Спасибо @Dai. Я немного новичок, поэтому на самом деле я не знаю правильного процесса для этого. Просто пытаюсь получить результат
5. @Dai вам нужно
borrow
определитьtransactionid
числа, вам нужноborrow_copy
определитьbookid
, и вам нужноbook_copy
определитьbookdescid
Ответ №1:
В качестве предисловия: помните, что в SELECT
инструкции логический порядок вычисления на самом деле:
FROM
WHERE
GROUP BY
HAVING
SELECT
ORDER BY
(Вы можете обвинить некоторых менеджеров IBM в 1970-х годах по причине why SELECT
comes first — они хотели, чтобы запросы выглядели как английский на естественном языке, чтобы PHB могли попытаться их понять, но в итоге язык запутался, и, к сожалению, сейчас это стандарт ISO с, вероятно, тысячами отдельных реализаций из сотенразных компаний и команд, так что это не изменится в ближайшее время)
И FROM
предложение может содержать бесконечно много других вложенных подзапросов (вообще говоря: если вы помещаете a SELECT x FROM y
в SELECT
предложение вместо FROM
предложения, то вы, вероятно, делаете что-то неправильно).
Прежде всего, документируйте таблицы с помощью CREATE TABLE
инструкций. Это проще, чем смотреть на скриншоты:
CREATE TABLE book (
bookDescId int,
title varchar,
subtitle varchar,
edition varchar,
etc varchar,
subjectId int,
CONSTRAINT PK_book PRIMARY KEY ( bookDescId )
)
CREATE TABLE book_copy (
bookDescId int,
bookId int,
CONSTRAINT PK_book_copy PRIMARY KEY ( bookId )
)
CREATE TABLE borrow (
transactionId int,
personId int,
etc date,
CONSTRAINT PK_borrow PRIMARY KEY ( transactionId ),
CONSTRAINT FK_borrow_TO_person ( personId ) REFERENCES person ( personId )
)
CREATE TABLE borrow_copy (
transactionId int,
bookId int
CONSTRAINT PK_borrow_copy PRIMARY KEY ( transactionId, bookId ),
CONSTRAINT FK_borrow_copy_TO_borrow ( transactionId ) REFERENCES borrow ( transactionId )
CONSTRAINT FK_borrow_copy_TO_book_copy ( bookId ) REFERENCES book_copy ( bookId )
)
Убрав это с пути, давайте работать вовне, а не внутрь:
Вот все транзакции заимствования от пользователя 14:
SELECT
borrow.*
FROM
borrow
WHERE
borrow.personId = 14
Мы можем INNER JOIN
borrow_copy
получить список bookIds
всех книг, которые когда-либо заимствовал person 14 (a LEFT OUTER JOIN
также будет работать, предполагая, что ваша база данных имеет реляционную целостность, но INNER JOIN
лучше выражает намерение):
SELECT
borrow_copy.bookId
FROM
borrow
INNER JOIN borrow_copy ON borrow.transactionId = borrow_copy.transactionId
WHERE
borrow.personId = 14
Затем мы можем INNER JOIN
повторить это с book_copy
помощью, чтобы получить bookDescId
из bookId
:
SELECT
borrow_copy.bookId,
book_copy.bookDescId
FROM
borrow
INNER JOIN borrow_copy ON borrow.transactionId = borrow_copy.transactionId
INNER JOIN book_copy ON book_copy.bookId = borrow_copy.bookId
WHERE
borrow.personId = 14
Затем INNER JOIN
снова, чтобы получить информацию о книге:
SELECT
borrow_copy.bookId,
book_copy.bookDescId,
book.title,
book.subtitle
FROM
borrow
INNER JOIN borrow_copy ON borrow.transactionId = borrow_copy.transactionId
INNER JOIN book_copy ON book_copy.bookId = borrow_copy.bookId
INNER JOIN book ON book.bookDescId = book_copy.bookDescId
WHERE
borrow.personId = 14
Поскольку вы просто хотите title
и subtitle
, удалите ненужные столбцы из SELECT
предложения и измените его с SELECT
на SELECT DISTINCT
на, чтобы удалить дубликаты (это одно из многих сокращений специального регистра в SQL, устраняющих необходимость в GROUP BY *
предложении):
SELECT DISTINCT
book.title,
book.subtitle
FROM
borrow_copy
INNER JOIN borrow ON borrow_copy.transactionId = borrow.transactionId
INNER JOIN book_copy ON borrow_copy.bookId = book_copy.bookId
INNER JOIN book ON book.bookDescId = book_copy.bookDescId
WHERE
personId = 14
из этих книг, которые позаимствовал человек 14, теперь покажите мне все названия, подзаголовки в таблице книг, которые имеют тот же subjectid, что и книги, которые позаимствовал человек 14.
Это просто: измените приведенный выше запрос, чтобы возвращать разные subjectId
значения, затем INNER JOIN
book
снова включите его (что потребует псевдонимирования book
таблицы):
SELECT DISTINCT
sameSubjectBooks.title,
sameSubjectBooks.subtitle
FROM
borrow_copy
INNER JOIN borrow ON borrow_copy.transactionId = borrow.transactionId
INNER JOIN book_copy ON borrow_copy.bookId = book_copy.bookId
INNER JOIN book AS b ON b.bookDescId = book_copy.bookDescId
INNER JOIN book AS sameSubjectBooks ON sameSubjectBooks.subjectId = b.subjectId
WHERE
personId = 14
Комментарии:
1. Большое спасибо за все это @Dai, действительно ценю это. Я также сохранил все это для справочных материалов, это здорово. Также отмечено относительно компоновки и порядка операций. Это намного чище и лаконичнее. Также отмечено относительно инструкций create table. Потрясающие заметки Я думаю, что здесь не хватает одной ключевой части, которая является концом, в котором говорится: из этих книг, которые одолжил человек 14, теперь покажите мне все названия, субтитры в таблице книг, которые имеют тот же subjectid, что и книги, которые одолжил человек 14. Это шаг 4 на моих скриншотах prnt.sc/vffukp
2. Предоставленное вами последнее утверждение просто возвращает все книги, которые когда-либо заимствовал person 14 — prnt.sc/vfgd6h Просто нужно понять следующий слой, который должен показывать все названия, субтитры для книг, которые имеют тот же subjectid, что и эти 2 записи
3. Еще раз большое спасибо @Dai, это сработало! Я вижу, как вы достигли этого сейчас самым чистым из возможных способов. Потрясающая нотация каждого шага, и я обязательно буду использовать этот случай снова в будущем.