Запрос естественного соединения SQL не выбирает ожидаемые результаты

Я пытаюсь сделать запрос с двумя естественными соединениями, но не получаю ожидаемых результатов. Я хочу получить данные работодателей, у которых есть назначенный проект. Кроме того, я хочу получить код проекта, название проекта и количество часов, которые сотрудник потратил на проект.

Это SQL-запрос, который я пытаюсь сделать:

SELECT empno, ename, sal, prono, hours, pname
FROM emp NATURAL RIGHT JOIN emppro NATURAL JOIN pro;

Это таблица emp:

EMPNO ENAME  JOB         MGR HIREDATE     SAL     COMM    DEPTNO
----- ---------- --------- ----- -------- ------- ------- ------
7369 SMITH   CLERK      7902 17/12/80     800             20
7499 ALLEN   SALESMAN   7698 20/02/81   1,600     300     30
7521 WARD    SALESMAN   7698 22/02/81   1,250     500     30
7566 JONES   MANAGER    7839 02/04/81   2,975             20
7654 MARTIN  SALESMAN   7698 28/09/81   1,250     1,400   30
7698 BLAKE   MANAGER    7839 01/05/81   2,850             30
7782 CLARK   MANAGER    7839 09/06/81   2,450             10
7788 SCOTT   ANALYST    7566 19/04/87   3,000             20
7839 KING    PRESIDENT   17/11/81       5,000             10
7844 TURNER  SALESMAN   7698 08/09/81   1,500      0      30
7876 ADAMS   CLERK      7788 23/05/87   1,100             20
7900 JAMES   CLERK      7698 03/12/81     950             30
7902 FORD    ANALYST    7566 03/12/81   3,000             20
7934 MILLER  CLERK      7782 23/01/82   1,300             10

Это таблица empro:

EMPNO      PRONO      HOURS
----- ---------- ----------
7499        1004     15
7499        1005     12
7521        1004     10
7521        1008      8
7654        1001     16
7654        1006     15
7654        1008      5
7844        1005      6
7934        1001      4

А это таблица плюсов:

PRONO       PNAME      LOC          DEPTNO
---------- ---------- ------------- ------
1001        P1         BOSTON         20
1004        P4         CHICAGO        30
1005        P5         CHICAGO        30
1006        P6         LOS ANGELES    30
1008        P8         NEW YORK       30

Если я делаю запрос с внутренними соединениями, он работает правильно, почему? Я думаю, что я неправильно понимаю естественное соединение...

Спасибо.


person Elias Garcia    schedule 24.02.2016    source источник


Ответы (2)


Никто не использует NATURAL JOIN именно по этим причинам. Ваш запрос:

SELECT empno, ename, sal, prono, hours, pname
FROM emp NATURAL RIGHT JOIN emppro NATURAL JOIN pro;

Эквивалентен этому запросу:

SELECT empno, ename, sal, prono, hours, pname
FROM emp 
RIGHT JOIN emppro ON emp.empno = emppro.empno
JOIN pro ON emppro.prono = pro.prono
  AND emp.deptno = pro.deptno -- This predicate is completely unexpected and wrong

Как вы можете видеть выше, вы случайно присоединились к столбцам DEPTNO, которые присутствуют как в emp, так и в pro, но вы не хотели присоединяться к этому столбцу.

Подумайте о своем исходном запросе следующим образом:

SELECT empno, ename, sal, prono, hours, pname
FROM A NATURAL JOIN pro;

Где A = (emp NATURAL RIGHT JOIN emppro). Таким образом, при соединении pro с A есть два общих столбца, которые имеют A и pro.

person Lukas Eder    schedule 24.02.2016
comment
Вау, спасибо! Четкий ответ, я не понял, что ошибка. Итак, когда я использую естественное соединение, оно соответствует всем столбцам с одинаковым именем, верно? Я думал, что это соответствует только предыдущей таблице. - person Elias Garcia; 25.02.2016
comment
Да: все столбцы с одинаковым именем. Я обновлю ответ и объясню, почему. - person Lukas Eder; 25.02.2016
comment
Хорошо, теперь я это ясно понимаю. Очень понятное объяснение, как и раньше, спасибо! - person Elias Garcia; 25.02.2016

NATURAL JOIN - это просто ошибка, ожидающая своего появления (как, по-видимому, и происходит в вашем случае). Он выбирает столбцы для объединения на основе имен в связанных таблицах/подзапросах. Он даже не использует объявленные отношения внешнего ключа. Мне это кажется очень плохой идеей. Просто забудьте, что он существует.

Итак, используйте вместо этого USING (или, если хотите, ON). Что-то вроде этого:

SELECT empno, ename, sal, prono, hours, pname
FROM emp RIGHT JOIN emppro
     emppro
     USING (EMPNO) INNER JOIN
     pro
     USING (PRONO);

Я тоже не фанат RIGHT JOIN. Я думаю, что LEFT JOIN легче следовать логически, особенно если вы изучаете SQL ("сохраняйте все строки в первой таблице и соответствующие строки во второй").

person Gordon Linoff    schedule 24.02.2016
comment
Спасибо, очень хороший совет для применения! - person Elias Garcia; 25.02.2016