Поддержка синтаксиса большого соединения

#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 инструкции логический порядок вычисления на самом деле:

  1. FROM
  2. WHERE
  3. GROUP BY
  4. HAVING
  5. SELECT
  6. 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, это сработало! Я вижу, как вы достигли этого сейчас самым чистым из возможных способов. Потрясающая нотация каждого шага, и я обязательно буду использовать этот случай снова в будущем.