Внешнее соединение более 1 таблицы

Допустим, у меня есть 5 таблиц следующим образом:

CREATE TABLE T1 (
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
CITY NUMERIC,
SALARY NUMERIC);

CREATE TABLE T2 (
CITY NUMERIC,
DISTRICT  NUMERIC);

CREATE TABLE T3 (
DISTRICT NUMERIC,
DOMAIN NUMERIC);

CREATE TABLE T4 (
DOMAIN NUMERIC,
DETAILS_BOOK NUMERIC);

CREATE TABLE T5 (
DETAILS_BOOK NUMERIC,
FIRST_NAME VARCHAR2(100),
LAST_NAME VARCHAR2(100),
EMAIL VARCHAR2(100));

INSERT INTO T1 VALUES ('john', 'doe',1001,1000); 
INSERT INTO T1 VALUES ('jack', 'jill',1001,2000);
INSERT INTO T1 VALUES ('jeff', 'bush',1001,1500);

INSERT INTO T2 VALUES (1001,1);

INSERT INTO T3 VALUES (1,543);

INSERT INTO T4 VALUES (543,22);

INSERT INTO T5 VALUES (22,'john', 'doe','john@22.com');
INSERT INTO T5 VALUES (44,'john', 'doe','john@44.com');
INSERT INTO T5 VALUES (22,'jeff', 'bush','jeff@22.com');
INSERT INTO T5 VALUES (44,'jeff', 'bush','jeff@44.com');

Теперь я хочу, чтобы все записи из t1, с их зарплатами и электронными письмами, соответствовали таблицам t2, t3 и t4, так, чтобы результат был:

FIRST_NAME | LAST_NAME | SALARY | EMAIL
--------------------------------------------------
john       | doe       |  1000  | john@22.com
jeff       | bush      |  1500  | jeff@22.com
jack       | jill      |  2000  | (NULL)

то, что я получил так далеко, это:

SELECT T1.FIRST_NAME, T1.LAST_NAME,T1.SALARY,T5.EMAIL
FROM T1,T2,T3,T4,T5
WHERE   T1.FIRST_NAME = T5.FIRST_NAME (+)
and     T1.LAST_NAME = T5.LAST_NAME(+)
AND     T1.CITY = T2.CITY
AND     T2.DISTRICT = T3.DISTRICT
AND     T3.DOMAIN = T4.DOMAIN
AND     T4.DETAILS_BOOK = T5.DETAILS_BOOK

который возвращает только первые две строки.

1 ответ

Решение

Попробуйте это вместо этого:

SELECT 
  T1.FIRST_NAME, 
  T1.LAST_NAME,
  T1.SALARY,
  T5.EMAIL
FROM T1
LEFT JOIN T2  ON T1.CITY         = T2.CITY
LEFT JOIN T3  ON T2.DISTRICT     = T3.DISTRICT
LEFT JOIN T4  ON T3.DOMAIN       = T4.DOMAIN
LEFT JOIN T5  ON T4.DETAILS_BOOK = T5.DETAILS_BOOK
             AND T1.FIRST_NAME   = T5.FIRST_NAME
             AND T1.LAST_NAME    = T5.LAST_NAME;

SQL Fiddle Demo

Это даст вам:

| FIRST_NAME | LAST_NAME | SALARY |       EMAIL |
-------------------------------------------------
|       john |       doe |   1000 | john@22.com |
|       jeff |      bush |   1500 | jeff@22.com |
|       jack |      jill |   2000 |      (null) |

Проблема в том, что INNER JOIN после OUTER JOIN делает ваши объединения работает как INNER потому что, внутренние объединения устраняют те непревзойденные ряды, которые идут от внешних объединений.

Обратите внимание: я использовал явный ANSI SQL-92 LEFT OUTER JOIN синтаксис, вместо старого неявного OUTER а также INNER присоединиться к синтаксису, который вы использовали в своем запросе.

Пожалуйста, попробуйте использовать LEFT OUTER JOIN вместо старого синтаксиса внешнего соединения, и избежать INNER JOIN после OUTER JOINs.

Для более подробной информации, смотрите эти:


Обновить:

Когда у вас есть много ссылок на таблицы в FROM оговорка с JOIN между ними каждая таблица соединяется со следующей таблицей, начиная с FROM пункт1, приводит к временному набору результатов, затем этот временный набор результатов объединяется со следующей таблицей и так далее. В случае OUTER JOINесть левое или правое:

  • LEFT JOIN будет включать эти несопоставленные строки из левой таблицы, где, как,
  • RIGHT JOIN будет включать эти несопоставленные строки из правой таблицы.

В зависимости от данных, которые вы хотите выбрать, вы должны следить за этими таблицами с двух сторон JOIN оператор и порядок их.


1:Это просто логический порядок обработки запросов, но в фактическом порядке всегда до оптимизатора запросов.

Другие вопросы по тегам