Опубликован: 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

Александра Каева
Александра Каева
Евгений Вершинин
Евгений Вершинин
Россия, Нижний Новгород, Нижегородский государственный технический университет, 2008
Aleksandr Arshinskyi
Aleksandr Arshinskyi
Россия