ИСПОЛЬЗОВАНИЕ HAVING

Выдать номера деталей для всех деталей, поставляемых более чем одним поставщиком (тот же пример, что и в 5.2.5).

SELECT НОМЕР_ДЕТАЛИ

FROM SP

GROUP BY НОМЕР_ДЕТАЛИ

HAVING COUNT (*)>1;

Результат:

НОМЕР_ДЕТАЛИ
P1 Р2 Р4 Р5

Фраза HAVING играет такую же роль для групп, что и фраза WHERE для строк. (Конечно, если специфицирована фраза HAVING, то должна быть специфицирована и фраза GROUP BY.) Иными словами, HAVING используется для того, чтобы исключать группы, точно так же, как WHERE используется для исключения строк. Выражение во фразе HAVING должно принимать единственное значение для группы.

В примере 5.2.5 уже было показано, что этот запрос может быть сформулирован без GROUP BY (и без HAVING) с использованием коррелированного подзапроса. Однако пример 5.2.5 в действительности основан на несколько ином восприятии логики, связанной с определением ответа на этот вопрос. Можно также сформулировать запрос, используя по существу ту же логику, что и в варианте GROUP BY/HAVING, но без явного использования фраз GROUP BY и HAVING вообще:

SELECТ DISTINCT НОМЕР_ДЕТАЛИ

FROM SP SPX

WHERE 1 <

(SELECT COUNT (*)

FROM SP SPY

WHERE SPY.НОМЕР_ДЕТАЛИ = SPX.HOMEP_ДЕТАЛИ);

Следующий вариант, в котором вместо SPX используется таблица Р, является, вероятно, более ясным:

SELECT НОМЕР_ДЕТАЛИ

FROM Р

WHERE 1 <

(SELECT COUNT (НОМЕР_ПОСТАВЩИКА)

FROM SP

WHERE НОМЕР_ДЕТАЛИ = P. НОМЕР_ДЕТАЛИ);

Еще одна формулировка связана с использованием EXISTS:

SELECT НОМЕР_ДЕТАЛИ

FROM P

WHERE EXISTS

(SELECT *

FROM SP SPX

WHERE SPX. НОМЕР_ДЕТАЛИ = Р. НОМЕР_ДЕТАЛИ

AND EXISTS

(SELECT *

FROM SP SPY

WHERE SPY. НОМЕР_ДЕТАЛИ = Р. НОМЕР_ДЕТАЛИ

AND SPY. НОМЕР_ПОСТАВЩИК Ø= SPX. НОМЕР_

ПОСТАВЩИКА);

Все эти альтернативные варианты являются в некотором отношении более предпочтительными по сравнению с вариантом GROUP BY/HAVING в связи с тем, что они по крайней мере логически более понятны и, в частности, не требуют этих дополнительных языковых конструкций. Из первоначальной формулировки задачи на естественном языке — «Выдать номера деталей для всех деталей, поставляемых более чем одним поставщиком» — без сомнения, не ясно, что группирование само по себе—это то, что необходимо для ответа на данный вопрос, и в нем, действительно, нет необходимости. Не является также непосредственно очевидным, что необходимо условие HAVING, а не условие WHERE. Вариант GROUP-BY/HAVING более похож на процедурное предписание для решения задачи, чем просто на ясную логическую формулировку ее существа. С другой стороны, нельзя опровергнуть тот факт, что вариант GROUP-BY/HAVING наиболее лаконичен. Далее, в свою очередь имеются некоторые задачи такого же общего характера, для которых GROUP BY и HAVING просто неадекватны, в силу чего следует использовать один из альтернативных подходов. Пример такой задачи представлен в упражнении 5.24.

Наконец, конструкции GROUP BY свойственно серьезное ограничение — она работает только на одном уровне. Невозможно разбить каждую из этих групп на группы более низкого уровня и т. д., а затем применить некоторую стандартную функцию, например SUM или AVG на каждом уровне группирования[16].