Опубликован: 28.12.2011 | Уровень: для всех | Доступ: свободно
Лекция 8:

Соединения таблиц в предложении SELECT

Синтаксис для операции соединения, разрешенный с версии 9

Приводимый ранее способ записи полуоткрытого соединения является собственным решением Oracle (он взят из потерявшего силу стандарта SQL 1986 года и сейчас является нестандартизованным элементом диалекта SQL Oracle). В сложных запросах он может оказаться неудобочитаемым и провоцировать ошибки программирования. С версии 9 Oracle можно (и рекомендуется) для записи разных видов соединений использовать специально разработанные в стандарте SQL:1999 синтаксические конструкции. Они рассматриваются ниже.

Закрытые соединения

Пример записи обычного (внутреннего, или закрытого) соединения в соответствии с SQL:1999:

SELECT e.ename, d.dname 
FROM   emp e
       INNER JOIN
       dept d
       ON ( e.deptno = d.deptno )
;

Обратите внимание, что такая формулировка разрешает привести в конструкции ON любое условное выражение (<=, <>, LIKE и так далее), например:

SELECT e.ename, e.sal, s.grade
FROM   emp e
       INNER JOIN
       salgrade s
       ON ( e.sal BETWEEN s.losal AND s.hisal )
;

Если же, как в предпоследнем случае, речь идет об эквисоединении (сравнении на совпадение величин) с одинаковыми названиями столбцов приравниваемых значений, годится и иная формулировка:

SELECT e.ename, d.dname 
FROM   emp e 
       INNER JOIN
       dept d 
       USING ( deptno )
;

У формулировки INNER JOIN … USING есть отличие от формулировки INNER JOIN … ON: во внутреннем декартовом произведении строк таблиц, которое строится фразой FROM в соответствии с логической схемой обработки предложения SELECT (приводилась выше) автоматически удаляются повторяющиеся столбцы. Это свойство унаследовано от реляционного соединения, где из результата автоматически удаляются одинаковые атрибуты (это не то же, что одинаково названные столбцы в таблицах SQL).

Упражнение. Сравните два результата, работы фразы FROM (в приводимых запросах кроме действий во фразе FROM по сути ничего не делается):

SELECT * FROM emp e INNER JOIN dept d ON e.deptno = d.deptno;
SELECT * FROM emp INNER JOIN dept USING ( deptno );

Как следствие (вполне логичное) соединения столбцы, участвующие в соединении, не требуют уточнения именем таблицы при ссылке на них в других местах предложения, например:

SELECT e.ename, d.dname, deptno
FROM   emp e
       INNER JOIN
       dept d
       USING ( deptno )
;

С другой стороны, когда заходит речь о самосоединении, это может приводить к проблеме:

SQL> SELECT * FROM dept INNER JOIN dept USING ( deptno );
SELECT * FROM dept INNER JOIN dept USING ( deptno )
                                           *
ERROR at line 1:
ORA-00918: column ambiguously defined

Успокаивает то, что с точки зрения приложения подобные запросы редко имеют смысл. Избавиться от этой ошибки Oracle можно введением псевдонимов. Следующие два запроса не приведут к ошибке:

SELECT * FROM dept a INNER JOIN dept b USING ( deptno ); 
SELECT * 
FROM   dept
       INNER JOIN
       ( SELECT * FROM dept )
       USING ( deptno )
; 

Первый из них формально, а второй фактически не будет считаться самосоединением.

Два полуоткрытых и открытое соединения

Примеры (внешних) полуоткрытых соединений:

SELECT e.ename, d.dname 
FROM   emp e 
       LEFT OUTER JOIN
       dept d 
       USING ( deptno )
;
SELECT e.ename, d.dname 
FROM   emp e 
       RIGHT OUTER JOIN
       dept d 
       USING ( deptno )
;

Пример (внешнего) открытого соединения:

SELECT e.ename, d.dname 
FROM   emp e 
       FULL OUTER JOIN
       dept d 
       USING ( deptno )
;

Последнее предложение не имеет равносильной записи в "старом" синтаксисе Oracle.

Ярослав Прозоров
Ярослав Прозоров

В лекции № 7 "Введение в Oracle SQL" в подразделе "Несамостоятельность группировки с обобщениями ROLLUP, CUBE и GROUPING SETS"  представленная таблица сравнения содержит ошибки - окончания запросов пропущены. Видимо, ошибки вызваны некорректным переносом материала лекции.

Володимир Миколайчук
Володимир Миколайчук
Помогите разобраться поетапно с логикой запроса
-------TOOLS
NAME PRICE TYPE
drill 155 A
sawzall 192 N
mitre saw 292 M
router 86 I
RAD 145 M
jigsaw 128 I
screwdriver 77 P
------TOOL_TYPES
TYPE USAGE
A Always
I Often
M Sometimes
N Rarely
P Never

Запрос SQL:
SELECT t.type, SUM(t.price)
FROM tools t
GROUP BY t.type
HAVING SUM(t.price) >= (SELECT AVG(price)
FROM tools
WHERE type IN (SELECT type
FROM tool_types
WHERE usage = 'Often'));

И сколько строк он все таки вернет
Жанбек Сарсенов
Жанбек Сарсенов
Россия, Москва, Московский Государственный Университет имени Ломоносова М.В., 2002