Запрос с эквивалентностью соединения? - PullRequest
5 голосов
/ 21 ноября 2011

Являются ли эти два запроса эквивалентными (если предположить, что данные в таблице различны / различны)?Существуют ли сценарии, в которых они будут возвращать разные результаты?

Запрос 1:

select * from tablea a
left join tableb b on a.keyacol = b.keybcol
inner join tablec c on c.keyccol = b.keybcol;

Запрос 2:

select * from tablea a
left join (
select b.*, c.* from tableb b
inner join tablec c on c.keyccol = b.keybcol
) sub on a.keyacol = sub.keybcol;

Ответы [ 3 ]

7 голосов
/ 21 ноября 2011

Нет, они не эквивалентны. Пример:

CREATE TABLE a
( keya int ) ;

CREATE TABLE b
( keyb int ) ;

CREATE TABLE c
( keyc int ) ;

INSERT INTO a
  VALUES
  (1) ;

INSERT INTO b
  VALUES
  (1),(2) ;

INSERT INTO c
  VALUES
  (2) ;

Результаты:

SELECT * 
FROM  a
  LEFT JOIN b 
    ON a.keya = b.keyb
  INNER JOIN c 
    ON c.keyc = b.keyb ;

Result
----------------------
| keya | keyb | keyc |
----------------------


SELECT * 
FROM a
  LEFT JOIN 
    ( SELECT b.*, c.* 
      FROM  b
        INNER JOIN c 
          ON c.keyc = b.keyb
    ) sub 
    ON a.keya = sub.keyb ;

Result
----------------------
| keya | keyb | keyc |
----------------------
|   1  | NULL | NULL |
----------------------

Что касается того, почему это происходит, a LEFT JOIN b INNER JOIN c анализируется как (a LEFT JOIN b) INNER JOIN c, что эквивалентно (a INNER JOIN b) INNER JOIN c, поскольку условие объединения INNER отменяет соединение LEFT.

Вы также можете написать второй запрос в этой форме - без подзапроса - который анализируется как a LEFT JOIN (b INNER JOIN c) из-за различного размещения предложений ON:

SELECT * 
FROM a
  LEFT JOIN 
        b
      INNER JOIN c 
        ON c.keyc = b.keyb
    ON a.keya = b.keyb ;

Result
----------------------
| keya | keyb | keyc |
----------------------
|   1  | NULL | NULL |
----------------------
3 голосов
/ 21 ноября 2011

Они не эквивалентны.

По сути, здесь есть четыре сценария для записей на A:

  1. существуют соответствующие записи на B и C;
  2. соответствующие записи существуют на B, но не на C;
  3. соответствующие записи существуют на C, но не на B;
  4. соответствующие записи не существуют на B или C.

Оба запроса вернут одинаковые значения для сценария 1.

Однако они будут возвращать разные значения для других сценариев - внутреннее объединение значения B со значением C в первом запросе означает, что вы будете пытаться соединить нулевое значение со значением C в других сценариях. .

3 голосов
/ 21 ноября 2011

Ключевое слово INNER JOIN возвращает строки, если в них есть хотя бы одно совпадение обе таблицы / выборы. Если в tableb есть строки, которые не имеют совпадения в tablec, эти строки НЕ будут перечислены.

Ключевое слово LEFT JOIN возвращает все строки из левой таблицы (tablea), даже если в правой таблице нет совпадений (tableb или sub выбор).

Поскольку левое объединение возвращает все строки, два запроса могут отличаться, если во внутреннем объединении нет совпадений из первого запроса. Эти строки не будут выбраны в первом запросе, но появятся во втором, так как используется левое соединение.

Еще одна вещь, которая может отличаться, это колонны. Но начиная с select * from вы будете выбирать все столбцы из всех таблиц / выборов и:

  • Запрос 1 возвращает все столбцы из tablea, tableb и tablec
  • Запрос 2 возвращает все столбцы из tablea и sub выбора (возвращает все столбцы из tableb и tablec) = возвращает все столбцы из tablea, tableb и tablec

это не проблема.

Итак НЕТ , они эквивалентны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...