13.2.9.2 Оператор JOIN
MySQL поддерживает следующий синтаксис для части table_references в операторах SELECT, а также в операторах DELETE и UPDATE с несколькими таблицами:
table_references:
escaped_table_reference [, escaped_table_reference] ...
escaped_table_reference: {
table_reference
| { OJ table_reference }
}
table_reference: {
table_factor
| joined_table
}
table_factor: {
tbl_name [PARTITION (partition_names)]
[[AS] alias] [index_hint_list]
| table_subquery [AS] alias
| ( table_references )
}
joined_table: {
table_reference [INNER | CROSS] JOIN table_factor [join_specification]
| table_reference STRAIGHT_JOIN table_factor
| table_reference STRAIGHT_JOIN table_factor ON search_condition
| table_reference {LEFT|RIGHT} [OUTER] JOIN table_reference join_specification
| table_reference NATURAL [{LEFT|RIGHT} [OUTER]] JOIN table_factor
}
join_specification: {
ON search_condition
| USING (join_column_list)
}
join_column_list:
column_name[, column_name] ...
index_hint_list:
index_hint[ index_hint] ...
index_hint: {
USE {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] ([index_list])
| {IGNORE|FORCE} {INDEX|KEY}
[FOR {JOIN|ORDER BY|GROUP BY}] (index_list)
}
index_list:
index_name [, index_name] ...
Ссылка на таблицу также известна как выражение соединения.
Ссылка на таблицу (если она относится к разграниченной таблице) может содержать оператор PARTITION, включая список разделённых запятыми разделов, подразделов или обоих. Этот вариант следует за именем таблицы и предшествует любому объявлению псевдонима. В результате этого варианта строки выбираются только из указанных разделов или подразделов. Разделы или подразделы, не указанные в списке, игнорируются. Дополнительную информацию и примеры см. в разделе 22.5 «Выбор разделов».
Синтаксис table_factor в MySQL расширен по сравнению со стандартным SQL. Стандартный SQL допускает только table_reference, а не список их внутри пары скобок.
Это расширение является консервативным, если каждая запятая в списке элементов table_reference рассматривается как эквивалент внутреннего соединения. Например:
SELECT * FROM t1 LEFT JOIN (t2, t3, t4)
ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)
эквивалентно:
SELECT * FROM t1 LEFT JOIN (t2 CROSS JOIN t3 CROSS JOIN t4)
ON (t2.a = t1.a AND t3.b = t1.b AND t4.c = t1.c)
В MySQL, JOIN, CROSS
JOIN и INNER JOIN являются синтаксическими эквивалентами (они могут заменить друг друга). В стандартном SQL они не эквивалентны. INNER JOIN используется с оператором ON, CROSS JOIN — в остальных случаях.
В общем случае скобки можно игнорировать в выражениях соединения, содержащих только внутренние соединения. MySQL также поддерживает вложенные соединения. См. раздел 8.2.1.7 «Оптимизация вложенных соединений».
Можно указать подсказки индексов, чтобы повлиять на то, как оптимизатор MySQL использует индексы. Дополнительную информацию см. в разделе 8.9.4 «Подсказки индексов». Другие способы влияния на использование оптимизатором индексов — это подсказки оптимизатора и системная переменная optimizer_switch. См. раздел 8.9.3 «Подсказки оптимизатора» и раздел 8.9.2 «Переключаемые оптимизации».
В следующем списке описаны общие факторы, которые следует учитывать при написании соединений:
-
Ссылку на таблицу можно задать псевдонимом, используя
илиtbl_nameASalias_nametbl_name alias_name:SELECT t1.name, t2.salary FROM employee AS t1 INNER JOIN info AS t2 ON t1.name = t2.name; SELECT t1.name, t2.salary FROM employee t1 INNER JOIN info t2 ON t1.name = t2.name;
-
table_subqueryтакже известна как производная таблица или подзапрос в оператореFROM. См. раздел 13.2.10.8 «Производные таблицы». Такие подзапросы должны включать псевдоним, чтобы присвоить подзапросу имя таблицы. Приведён тривиальный пример:SELECT * FROM (SELECT 1, 2, 3) AS t1;
-
Максимальное количество таблиц, на которые можно ссылаться в одном соединении, равно 61. Это включает соединение, обрабатываемое с помощью объединения производных таблиц и представлений в операторе
FROMв блок внешнего запроса (см. раздел 8.2.2.4 «Оптимизация производных таблиц и ссылок на представления с объединением или материализацией»). -
INNER JOINи,(запятая) семантически эквивалентны в отсутствие условия соединения: оба создают декартово произведение между указанными таблицами (то есть каждая строка в первой таблице соединяется с каждой строкой во второй таблице).Однако приоритет оператора запятой ниже, чем у операторов
INNER JOIN,CROSS JOIN,LEFT JOINи так далее. Если вы смешиваете соединения с запятыми с другими типами соединений при наличии условия соединения, может произойти ошибка видаUnknown column '. Информация о решении этой проблемы приведена ниже в этом разделе.col_name' in 'on clause' search_condition, используемое сON, — это любое условное выражение, которое может быть использовано в оператореWHERE. Обычно операторONиспользуется для условий, определяющих, как соединять таблицы, а операторWHEREограничивает строки, которые нужно включить в результирующий набор.-
Если для правой таблицы в части
ONилиUSINGсоединенияLEFT JOINнет соответствующей строки, используется строка со всеми столбцами, установленными вNULL. Это можно использовать, чтобы найти строки в одной таблице, у которых нет аналогов в другой таблице:SELECT left_tbl.* FROM left_tbl LEFT JOIN right_tbl ON left_tbl.id = right_tbl.id WHERE right_tbl.id IS NULL;
Этот пример находит все строки в
left_tblсо значениемid, которого нет вright_tbl(то есть все строки вleft_tblбез соответствующих строк вright_tbl). См. раздел 8.2.1.8 «Оптимизация внешних соединений». -
Оператор
USING(перечисляет столбцы, которые должны существовать в обеих таблицах. Если таблицыjoin_column_list)aиbобе содержат столбцыc1,c2иc3, следующее соединение сравнивает соответствующие столбцы из двух таблиц:a LEFT JOIN b USING (c1, c2, c3)
Соединение двух таблиц семантически эквивалентно внутреннему соединению или внешнему соединению с оператором
USING, перечисляющим все столбцы, существующие в обеих таблицах.RIGHT JOINработает аналогичноLEFT JOIN. Чтобы сохранить совместимость кода между базами данных, рекомендуется использоватьLEFT JOINвместоRIGHT JOIN.-
Синтаксис
{ OJ ... }, показанный в описании синтаксиса соединения, существует только для совместимости с ODBC. Фигурные скобки в синтаксисе следует писать буквально; они не являются метасинтаксисом, как используется в других описаниях синтаксиса.SELECT left_tbl.* FROM { OJ left_tbl LEFT OUTER JOIN right_tbl ON left_tbl.id = right_tbl.id } WHERE right_tbl.id IS NULL;Вы можете использовать другие типы соединений в
{ OJ ... }, такие какINNER JOINилиRIGHT OUTER JOIN. Это помогает обеспечить совместимость с некоторыми сторонними приложениями, но не является официальным синтаксисом ODBC. STRAIGHT_JOINподобноJOIN, за исключением того, что левая таблица всегда считывается перед правой таблицей. Это можно использовать в тех (некоторых) случаях, когда оптимизатор соединений обрабатывает таблицы не оптимальным образом.
Некоторые примеры соединений:
SELECT * FROM table1, table2;
SELECT * FROM table1 INNER JOIN table2 ON table1.id = table2.id;
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id;
SELECT * FROM table1 LEFT JOIN table2 USING (id);
SELECT * FROM table1 LEFT JOIN table2 ON table1.id = table2.id
LEFT JOIN table3 ON table2.id = table3.id;
Естественные соединения и соединения с USING, включая варианты внешних соединений, обрабатываются в соответствии со стандартом SQL:2003.
-
Избыточные столбцы в соединении
NATURALне отображаются. Рассмотрим этот набор операторов:CREATE TABLE t1 (i INT, j INT); CREATE TABLE t2 (k INT, j INT); INSERT INTO t1 VALUES(1, 1); INSERT INTO t2 VALUES(1, 1); SELECT * FROM t1 NATURAL JOIN t2; SELECT * FROM t1 JOIN t2 USING (j);
В первом операторе
SELECTстолбецjприсутствует в обеих таблицах и, следовательно, становится столбцом соединения, поэтому, согласно стандарту SQL, он должен отображаться только один раз в выводе, а не дважды. Аналогично, во втором операторе SELECT столбецjуказан в фрагментеUSINGи должен отображаться только один раз в выводе, а не дважды.Таким образом, операторы генерируют такой вывод:
+------+------+------+ | j | i | k | +------+------+------+ | 1 | 1 | 1 | +------+------+------+ +------+------+------+ | j | i | k | +------+------+------+ | 1 | 1 | 1 | +------+------+------+
Удаление избыточных столбцов и упорядочение столбцов выполняется в соответствии со стандартом SQL, что приводит к такому порядку отображения:
Во-первых, объединённые общие столбцы двух соединённых таблиц в порядке их появления в первой таблице
Во-вторых, столбцы, уникальные для первой таблицы, в порядке их появления в этой таблице
В-третьих, столбцы, уникальные для второй таблицы, в порядке их появления в этой таблице
Единственный столбец результата, который заменяет два общих столбца, определяется с помощью операции объединения. То есть, для двух
t1.aиt2.aрезультирующий единственный столбец соединенияaопределяется какa = COALESCE(t1.a, t2.a), где:COALESCE(x, y) = (CASE WHEN x IS NOT NULL THEN x ELSE y END)
Если операция соединения — любая другая, столбцы результата соединения состоят из конкатенации всех столбцов соединённых таблиц.
Следствием определения объединённых столбцов является то, что для внешних соединений объединённый столбец содержит значение столбца, не являющегося
NULL, если один из двух столбцов всегдаNULL. Если ни один, ни оба столбца неNULL, оба общих столбца имеют одинаковое значение, поэтому не имеет значения, какой из них выбран в качестве значения объединённого столбца. Простой способ интерпретации этого заключается в том, что объединённый столбец внешнего соединения представлен общим столбцом внутренней таблицыJOIN. Предположим, что таблицыt1(a, b)иt2(a, c)имеют следующее содержимое:t1 t2 ---- ---- 1 x 2 z 2 y 3 w
Тогда для этого соединения столбец
aсодержит значенияt1.a:mysql>
SELECT * FROM t1 NATURAL LEFT JOIN t2;+------+------+------+ | a | b | c | +------+------+------+ | 1 | x | NULL | | 2 | y | z | +------+------+------+В отличие от этого, для этого соединения столбец
aсодержит значенияt2.a.mysql>
SELECT * FROM t1 NATURAL RIGHT JOIN t2;+------+------+------+ | a | c | b | +------+------+------+ | 2 | z | y | | 3 | w | NULL | +------+------+------+Сравните эти результаты с иначе эквивалентными запросами с
JOIN ... ON:mysql>
SELECT * FROM t1 LEFT JOIN t2 ON (t1.a = t2.a);+------+------+------+------+ | a | b | a | c | +------+------+------+------+ | 1 | x | NULL | NULL | | 2 | y | 2 | z | +------+------+------+------+mysql>
SELECT * FROM t1 RIGHT JOIN t2 ON (t1.a = t2.a);+------+------+------+------+ | a | b | a | c | +------+------+------+------+ | 2 | y | 2 | z | | NULL | NULL | 3 | w | +------+------+------+------+ -
Фрагмент
USINGможет быть переписан как фрагментON, который сравнивает соответствующие столбцы. Однако, хотяUSINGиONпохожи, они не совсем одинаковы. Рассмотрим следующие два запроса:a LEFT JOIN b USING (c1, c2, c3) a LEFT JOIN b ON a.c1 = b.c1 AND a.c2 = b.c2 AND a.c3 = b.c3
Что касается определения строк, удовлетворяющих условию соединения, оба соединения семантически идентичны.
Что касается определения столбцов для отображения при расширении
SELECT *, два соединения не являются семантически идентичными. СоединениеUSINGвыбирает объединённое значение соответствующих столбцов, в то время как соединениеONвыбирает все столбцы из всех таблиц. Для соединенияUSING,SELECT *выбирает эти значения:COALESCE(a.c1, b.c1), COALESCE(a.c2, b.c2), COALESCE(a.c3, b.c3)
Для соединения
ON,SELECT *выбирает эти значения:a.c1, a.c2, a.c3, b.c1, b.c2, b.c3
При внутреннем соединении
COALESCE(a.c1, b.c1)эквивалентно либоa.c1, либоb.c1, так как оба столбца имеют одинаковое значение. При внешнем соединении (таком какLEFT JOIN), один из двух столбцов может бытьNULL. Этот столбец опущается из результата. -
Фрагмент
ONможет ссылаться только на свои операнды.Пример:
CREATE TABLE t1 (i1 INT); CREATE TABLE t2 (i2 INT); CREATE TABLE t3 (i3 INT); SELECT * FROM t1 JOIN t2 ON (i1 = i3) JOIN t3;
Оператор завершается ошибкой
Unknown column 'i3' in 'on clause', так какi3является столбцом вt3, который не является операндом фрагментаON. Для обработки соединения перепишите оператор следующим образом:SELECT * FROM t1 JOIN t2 JOIN t3 ON (i1 = i3);
-
JOINимеет более высокий приоритет, чем оператор запятой (,), поэтому выражение соединенияt1, t2 JOIN t3интерпретируется как(t1, (t2 JOIN t3)), а не как((t1, t2) JOIN t3). Это влияет на операторы, использующие фрагментON, так как этот фрагмент может ссылаться только на столбцы в операндах соединения, а приоритет влияет на интерпретацию этих операндов.Пример:
CREATE TABLE t1 (i1 INT, j1 INT); CREATE TABLE t2 (i2 INT, j2 INT); CREATE TABLE t3 (i3 INT, j3 INT); INSERT INTO t1 VALUES(1, 1); INSERT INTO t2 VALUES(1, 1); INSERT INTO t3 VALUES(1, 1); SELECT * FROM t1, t2 JOIN t3 ON (t1.i1 = t3.i3);
JOINимеет более высокий приоритет по сравнению с оператором запятой, поэтому операндами фрагментаONявляютсяt2иt3. Так какt1.i1не является столбцом ни в одном из операндов, результатом является ошибкаUnknown column 't1.i1' in 'on clause'.Для обработки соединения используйте любой из этих способов:
-
Явно сгруппируйте первые две таблицы в скобки, чтобы операндами фрагмента
ONбыли(t1, t2)иt3:SELECT * FROM (t1, t2) JOIN t3 ON (t1.i1 = t3.i3);
-
Избегайте использования оператора запятой и используйте
JOINвместо него:SELECT * FROM t1 JOIN t2 JOIN t3 ON (t1.i1 = t3.i3);
Такая же интерпретация приоритета также применяется к операторам, которые смешивают оператор запятой с
INNER JOIN,CROSS JOIN,LEFT JOINиRIGHT JOIN, все из которых имеют более высокий приоритет, чем оператор запятой. -
Расширение MySQL по сравнению со стандартом SQL:2003 заключается в том, что MySQL позволяет квалифицировать общие (объединённые) столбцы
NATURALилиUSINGсоединений, тогда как стандарт этого не допускает.
© 2025 Oracle
Licensed under the GPLv2 License.