Рубрики
Без рубрики

ВНУТРЕННЕЕ СОЕДИНЕНИЕ SQL – Руководство для начинающих

Узнайте, как работает ВНУТРЕННЕЕ СОЕДИНЕНИЕ SQL и как его можно использовать для связывания строк, принадлежащих разным таблицам, и создания составного результирующего набора.

Автор оригинала: Vlad Mihalcea.

Вступление

В этой статье мы рассмотрим, как работает ВНУТРЕННЕЕ ОБЪЕДИНЕНИЕ в SQL и как мы можем использовать его для связывания строк, принадлежащих разным таблицам, и построения составных наборов результатов.

Таблицы базы данных

Давайте рассмотрим, что у нас есть две таблицы, post и post_comment , которые образуют связь один ко многим таблицам через столбец post_id Внешний ключ в таблице post_comment :

Таблица post содержит следующие 3 строки:

| id | title     |
|----|-----------|
| 1  | Java      |
| 2  | Hibernate |
| 3  | JPA       |

и в таблице post_comment есть следующие 3 записи:

| id | review    | post_id |
|----|-----------|---------|
| 1  | Good      | 1       |
| 2  | Excellent | 1       |
| 3  | Awesome   | 2       |

ВНУТРЕННЕЕ СОЕДИНЕНИЕ SQL

Предложение SQL JOIN позволяет связывать строки, принадлежащие разным таблицам. Например, ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ создаст декартово произведение, содержащее все возможные комбинации строк между двумя соединяющимися таблицами.

Хотя ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ полезно в определенных сценариях, в большинстве случаев вы хотите объединить таблицы на основе определенного условия. И вот тут в игру вступает ВНУТРЕННЕЕ СОЕДИНЕНИЕ.

ВНУТРЕННЕЕ СОЕДИНЕНИЕ SQL позволяет нам фильтровать декартово произведение соединения двух таблиц на основе условия, указанного в предложении ON.

Условие ВНУТРЕННЕГО СОЕДИНЕНИЯ SQL “всегда верно”

Если вы укажете условие “всегда верно”, ВНУТРЕННЕЕ СОЕДИНЕНИЕ не будет фильтровать объединенные записи, и результирующий набор будет содержать декартово произведение двух соединяемых таблиц.

Например, если мы выполним следующий запрос ВНУТРЕННЕГО СОЕДИНЕНИЯ SQL:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 1

Мы получим все комбинации post и post_comment записей:

| p.id    | pc.id      |
|---------|------------|
| 1       | 1          |
| 1       | 2          |
| 1       | 3          |
| 2       | 1          |
| 2       | 2          |
| 2       | 3          |
| 3       | 1          |
| 3       | 2          |
| 3       | 3          |

Таким образом, если условие предложения ON “всегда верно”, ВНУТРЕННЕЕ СОЕДИНЕНИЕ просто эквивалентно запросу ПЕРЕКРЕСТНОГО СОЕДИНЕНИЯ:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 1
ORDER BY p.id, pc.id

Условие ВНУТРЕННЕГО СОЕДИНЕНИЯ SQL “всегда ложно”

С другой стороны, если условие предложения ON “всегда ложно”, то все объединенные записи будут отфильтрованы, а результирующий набор будет пустым.

Итак, если мы выполним следующий запрос ВНУТРЕННЕГО СОЕДИНЕНИЯ SQL:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
INNER JOIN post_comment pc ON 1 = 0
ORDER BY p.id, pc.id

Мы не получим никакого результата обратно:

| p.id    | pc.id      |
|---------|------------|

Это связано с тем, что приведенный выше запрос эквивалентен следующему запросу ПЕРЕКРЕСТНОГО СОЕДИНЕНИЯ:

SELECT
   p.id AS "p.id",
   pc.id AS "pc.id"
FROM post p
CROSS JOIN post_comment
WHERE 1 = 0
ORDER BY p.id, pc.id

Предложение ВНУТРЕННЕГО СОЕДИНЕНИЯ SQL с использованием столбцов внешнего ключа и первичного ключа

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

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p
INNER JOIN post_comment pc ON pc.post_id = p.id
ORDER BY p.id, pc.id

При выполнении приведенного выше запроса ВНУТРЕННЕГО СОЕДИНЕНИЯ SQL мы получаем следующий набор результатов:

| p.id    | pc.post_id | pc.id      | p.title    | pc.review |
|---------|------------|------------|------------|-----------|
| 1       | 1          | 1          | Java       | Good      |
| 1       | 1          | 2          | Java       | Excellent |
| 2       | 2          | 3          | Hibernate  | Awesome   |

Таким образом, в набор результатов запроса включаются только записи, соответствующие условию предложения ON. В нашем случае результирующий набор содержит все записи post вместе с их записями post_comment . Строки post , с которыми не связано post_comment , исключаются, поскольку они не могут удовлетворять условию предложения ON.

Опять же, приведенный выше запрос ВНУТРЕННЕГО СОЕДИНЕНИЯ SQL эквивалентен следующему запросу ПЕРЕКРЕСТНОГО СОЕДИНЕНИЯ:

SELECT
   p.id AS "p.id",
   pc.post_id AS "pc.post_id",
   pc.id AS "pc.id",
   p.title AS "p.title",
   pc.review  AS "pc.review"
FROM post p, post_comment pc
WHERE pc.post_id = p.id

Выделенные строки-это те, которые удовлетворяют предложению WHERE, и только эти записи будут включены в результирующий набор. Это лучший способ визуализировать, как работает ВНУТРЕННЕЕ предложение СОЕДИНЕНИЯ.

| p.id | pc.post_id | pc.id | p.title   | pc.review |
|------|------------|-------|-----------|-----------|
| 1    | 1          | 1     | Java      | Good      |
| 1    | 1          | 2     | Java      | Excellent |
| 1    | 2          | 3     | Java      | Awesome   |
| 2    | 1          | 1     | Hibernate | Good      |
| 2    | 1          | 2     | Hibernate | Excellent |
| 2    | 2          | 3     | Hibernate | Awesome   |
| 3    | 1          | 1     | JPA       | Good      |
| 3    | 1          | 2     | JPA       | Excellent |
| 3    | 2          | 3     | JPA       | Awesome   |

Вывод

Предложение JOIN – это очень мощная функция SQL, позволяющая создавать результирующие наборы, объединяющие записи, принадлежащие разным таблицам.

В то время как ПЕРЕКРЕСТНОЕ СОЕДИНЕНИЕ позволяет создавать декартово произведение записей, принадлежащих двум соединяемым таблицам, ВНУТРЕННЕЕ СОЕДИНЕНИЕ позволяет фильтровать декартово произведение и возвращать только соединенные записи, соответствующие заданному условию фильтрации.