Порядок выполнения операторов UNION, EXCEPT, INTERSECT
В связи с упражнением 6 (SELECT) рейтингового этапа возник вопрос относительно старшинства операций UNION, EXCEPT и INTERSECT. Логический порядок выполнения этих операций, который приводится в книге Мартина Грабера [4] “Справочное руководство по SQL”, выглядит так:
- UNION, EXCEPT
- INTERSECT
В предположении, что логический порядок выполнения операций соответствует их старшинству, получается, что старшинство операций UNION и EXCEPT идентично и, следовательно, они должны выполняться в том порядке, в котором записаны, если этот порядок не изменяется скобками. При этом обе операции выполняются раньше, чем INTERSECT, т.е. они старше.
Рассмотрим три простых запроса, которые будем комбинировать различными способами, чтобы убедиться в этом:
--Модели и типы продукции производителя B       
SELECT model, type FROM Product WHERE maker='B';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
| model | type | 
|---|---|
| 1121 | PC | 
| 1750 | Laptop | 
--Модели ноутбуков  
SELECT model, type FROM Product WHERE type='Laptop';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
| model | type | 
|---|---|
| 1298 | Laptop | 
| 1321 | Laptop | 
| 1750 | Laptop | 
| 1752 | Laptop | 
--Модели ПК  
SELECT model, type FROM Product WHERE type='PC';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
| model | type | 
|---|---|
| 1121 | PC | 
| 1232 | PC | 
| 1233 | PC | 
| 1260 | PC | 
| 2111 | PC | 
| 2112 | PC | 
Давайте сначала проверим первое утверждение. Если операция EXCEPT старше операции UNION, то запросы
SELECT model, type FROM Product WHERE maker='B'  
UNION  
SELECT model, type FROM Product WHERE type='Laptop'  
EXCEPT  
SELECT model, type FROM Product WHERE type='PC';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
и
(SELECT model, type FROM Product WHERE maker='B'  
UNION  
SELECT model, type FROM Product WHERE type='Laptop')  
EXCEPT  
SELECT model, type FROM Product WHERE type='PC';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
должны нам дать разные результаты. Однако это не так, и мы получаем один и тот же результирующий набор:
| model | type | 
|---|---|
| 1298 | Laptop | 
| 1321 | Laptop | 
| 1750 | Laptop | 
| 1752 | Laptop | 
Аналогично, если операция UNION старше операции EXCEPT, то запросы
SELECT model, type FROM Product WHERE type='Laptop'
EXCEPT  
SELECT model, type FROM Product WHERE type='PC'  
UNION  
SELECT model, type FROM Product WHERE maker='B';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
и
(SELECT model, type FROM Product WHERE type='Laptop'  
EXCEPT  
SELECT model, type FROM Product WHERE type='PC')  
UNION  
SELECT model, type FROM Product WHERE maker='B';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
должны нам дать разные результаты. И тут мы получаем одинаковый результат:
| model | type | 
|---|---|
| 1121 | PC | 
| 1298 | Laptop | 
| 1321 | Laptop | 
| 1750 | Laptop | 
| 1752 | Laptop | 
Итак, операции UNION и EXCEPT эквивалентны по старшинству.
Проверим теперь старшинство операции INTERSECT по отношению к другим операторам (в тестах можно взять любую из них, т.к. они имеют один и тот же порядок).
Если INTERSECT “младше” или эквивалентен UNION, то запросы
SELECT model, type FROM Product WHERE maker='B'  
UNION  
SELECT model, type FROM Product WHERE type='Laptop'  
INTERSECT  
SELECT model, type FROM Product WHERE type='PC';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
и
(SELECT model, type FROM Product WHERE maker='B'  
UNION  
SELECT model, type FROM Product WHERE type='Laptop')  
INTERSECT  
SELECT model, type FROM Product WHERE type='PC';| [[ column ]] | 
|---|
| NULL [[ value ]] | 
должны дать одинаковые результаты. Однако мы получаем разные результирующие наборы. Первый запрос дает
| model | type | 
|---|---|
| 1121 | PC | 
| 1750 | Laptop | 
в то время как второй
| model | type | 
|---|---|
| 1121 | PC | 
Вывод. Логический порядок, приведенный в начале статьи не соответствует старшинству операций, и, на мой взгляд, его следует поменять на обратный:
- INTERSECT
- UNION, EXCEPT