Опубликован: 10.10.2005 | Уровень: специалист | Доступ: платный | ВУЗ: Московский государственный университет имени М.В.Ломоносова
Лекция 5:

Группировка и условия раздела HAVING, порождаемые и соединенные таблицы

Предикат exists
SELECT DEPT.DEPT_NO
FROM DEPT, EMP
WHERE DEPT.DEPT_NO = EMP.DEPT_NO
GROUP BY DEPT.DEPT_NO
HAVING EXISTS (SELECT *
	FROM EMP EMP1
	WHERE EMP1.DEPT_NO <> DEPT.DEPT_NO
	GROUP BY EMP1.DEPT_NO 
	HAVING MAX (EMP1.EMP_SAL)= AVG (EMP.EMP_SAL));
15.9. Найти номера отделов, в которых средний размер зарплаты служащих равен максимальному размеру зарплаты служащих какого-либо другого отдела (другая формулировка для примера 15.7).

В этой формулировке основной интерес представляет подзапрос, в котором корреляция с внешним запросом происходит через вызов агрегатной функции от группы строк внешнего запроса. Здесь также можно избавиться от разделов GROUP BY и HAVING во внешнем запросе ( пример 15.9.1):

SELECT DEPT.DEPT_NO
FROM DEPT
WHERE EXISTS (SELECT EMP.DEPT_NO
	FROM EMP
	WHERE EMP.DEPT_NO <> DEPT.DEPT_NO
	GROUP BY EMP.DEPT_NO 
	HAVING MAX (EMP.EMP_SAL)= 
	  (SELECT AVG (EMP1.EMP_SAL)
	    FROM EMP EMP1
	    WHERE EMP1.DEPT_NO = DEPT.DEPT_NO));
15.9.1.
Предикат unique
SELECT DEPT.DEPT_NO, AVG (EMP.EMP_SAL)
FROM DEPT, EMP
WHERE DEPT.DEPT_NO = EMP.DEPT_NO
GROUP BY DEPT.DEPT_NO
HAVING UNIQIUE (SELECT AVG (EMP1.EMP_SAL)
	FROM EMP EMP1
	WHERE EMP1.DEPT_NO IS NOT NULL
	GROUP BY EMP1.DEPT_NO 
	HAVING AVG (EMP1.EMP_SAL) = AVG (EMP.EMP_SAL));
15.10. Найти номера отделов и средний размер зарплаты служащих для таких отделов, где средний размер зарплаты служащих отличается от среднего размера зарплаты всех других отделов.

Вот альтернативная формулировка этого запроса с использованием предиката NOT EXISTS ( пример 15.10.1):

SELECT DEPT.DEPT_NO, AVG (EMP.EMP_SAL)
FROM DEPT, EMP
WHERE DEPT.DEPT_NO = EMP.DEPT_NO
GROUP BY DEPT.DEPT_NO
HAVING NOT EXISTS (SELECT EMP1.DEPT_NO
	FROM EMP EMP1
	WHERE EMP1.DEPT_NO <> DEPT.DEPT_NO
	GROUP BY EMP1.DEPT_NO 
	HAVING AVG (EMP1.EMP_SAL)= AVG (EMP.EMP_SAL));
15.10.1.
Предикаты сравнения с квантором
SELECT DEPT_NO, AVG (CURRENT_DATE - EMP_BDATE)
FROM EMP
WHERE DEPT_NO IS NOT NULL
GROUP BY DEPT_NO
HAVING AVG (CURRENT_DATE - EMP_BDATE)< SOME
	(SELECT AVG (CURRENT_DATE - EMP1.EMP_BDATE) 
	  FROM EMP EMP1
	  WHERE EMP1.DEPT_NO IS NOT NULL
	  GROUP BY EMP1.DEPT_NO);
15.11. Найти номера отделов и средний возраст служащих для таких отделов, что найдется хотя бы один другой отдел, средний возраст служащих которого больше, чем в данном.

Напомним, что "ниладическая" функция CURRENT_DATE выдает текущую дату, и, следовательно, значением выражения CURRENT_DATE - EMP_BDATE является интервал, представляющий текущий возраст служащего. На наш взгляд, формулировка этого запроса несколько упрощается, если пользоваться предикат предикатом EXISTS ( пример 15.11.1):

SELECT DEPT_NO, AVG (CURRENT_DATE - EMP_BDATE)
FROM EMP
WHERE DEPT_NO IS NOT NULL
GROUP BY DEPT_NO
HAVING EXISTS (SELECT EMP1.DEPT_NO
	FROM EMP EMP1
	WHERE EMP1.DEPT_NO IS NOT NULL
	GROUP BY EMP1.DEPT_NO
	HAVING AVG (CURRENT_DATE - EMP1.EMP_BDATE) >
	  AVG (CURRENT_DATE - EMP.EMP_BDATE));
15.11.1.
SELECT DEPT_NO, AVG (CURRENT_DATE - EMP_BDATE)
FROM EMP
WHERE DEPT_NO IS NOT NULL
GROUP BY DEPT_NO
HAVING AVG (CURRENT_DATE - EMP_BDATE) <= ALL
	(SELECT AVG (CURRENT_DATE - EMP_BDATE)
	  FROM EMP
	  WHERE DEPT_NO IS NOT NULL
	  GROUP BY DEPT_NO);
15.12. Найти номера отделов и средний возраст служащих для отделов с минимальным средним возрастом служащих.

Этот запрос легко формулируется в более понятном виде с использованием предиката NOT EXISTS ( пример 15.12.1):

SELECT DEPT_NO, AVG (CURRENT_DATE - EMP_BDATE)
FROM EMP
WHERE DEPT_NO IS NOT NULL
GROUP BY DEPT_NO
HAVING NOT EXISTS (SELECT EMP1.DEPT_NO
	FROM EMP EMP1
	WHERE EMP1.DEPT_NO IS NOT NULL
	GROUP BY EMP1.DEPT_NO
	HAVING AVG (CURRENT_DATE - EMP1.EMP_BDATE) <
	  AVG (CURRENT_DATE - EMP.EMP_BDATE));
15.12.1.
Предикат distinct
SELECT DEPT.DEPT_NO
FROM DEPT, EMP EMP1, EMP EMP2
WHERE DEPT.DEPT_NO = EMP1.DEPT_NO AND
	DEPT.DEPT_MNG = EMP2.EMP_NO
GROUP BY DEPT.DEPT_NO, EMP2.EMP_BDATE 
HAVING (EMP2.EMP_BDATE, AVG (EMP1.EMP_SAL)) DISTINCT FROM
	(SELECT EMP2.EMP_BDATE, AVG (EMP1.EMP_SAL)
	  FROM DEPT DEPT1, EMP EMP1, EMP EMP2
	  WHERE DEPT1.DEPT_NO = EMP1.DEPT_NO AND
	  DEPT1.DEPT_MNG = EMP2.EMP_NO AND
	  DEPT1.DEPT_NO <> DEPT.DEPT_NO
	  GROUP BY DEPT.DEPT_NO, EMP2.EMP_BDATE);
15.13. Найти номера отделов, которые можно отличить от любого другого отдела по дате рождения руководителя и среднему размеру зарплаты.
Алексей Ковтун
Алексей Ковтун

При попытке исполнения запроса:

CREATE DOMAIN EMP_NO AS INTEGER

    CHECK (VALUE BETWEEN 1 AND 10000);

Выдается ошибка: Неизвестный тип объекта "DOMAIN" в интсрукции CREATE, DROP или ALTER. 

Используется SQL Server MS SQL 2008R2

Александра Каева
Александра Каева