Среди операций, которые поддерживаются в OQL и еще не упоминались в этом разделе, содержатся “множественные” операции union , intersect и except для всех видов коллекций; операции с кванторами for all и exists ; операции сортировки и группирования (sort и group by ); агрегатные операции count , sum , min , max и avg . Мы не будем подробно обсуждать эти операции47, но приведем пример достаточно сложного запроса, в котором некоторые из операций используются.
Пример 2.15. Найти название отдела, в котором работают служащие, средняя зарплата которых меньше средней зарплаты служащих любого другого отдела (для простоты предположим, что размер средней зарплаты служащих во всех отделах различается).
Будем строить запрос по шагам с использованием конструкции языка OQL define для вычисления промежуточных результатов.
Шаг 1. Построить множество объектов-служащих, для которых известен номер отдела.
define EMPLOYEES_D () AS
SELECT E FROM EMPLOYEES E
WHERE E.WORKS IS NOT nil
Шаг 2. Сгруппировать служащих с известными номерами отделов по номерам отделов и вычислить размер средней зарплаты для каждого отдела.
DEFINE DEPT_AVG_SAL () AS
SELECT DEPT_NO,
AVG_SAL : avg (SELECT X.E.EMP_SAL FROM PARTITION X )
FROM EMPLOYEES_D () E
GROUP BY DEPT_NO : E.DEPT_NO
Типомрезультатаэтогозапросаявляетсяbag < struct { integer DEPT_NO; decimal AVG_SAL } > . Операция group by расщепляет множество служащих на разделы (partitions ) в соответствии с критерием группирования (номеру отдела, в котором работает служащий). В разделе SELECT для каждого раздела вычисляется размер средней зарплаты сотрудников.
Шаг 3. Отсортировать полученное мультимножество по значениям атрибута AVG _ SAL .
DEFINE SORTED_DEPT_AVG_SAL () AS
SELECT S FROM DEPT_AVG_SAL () AS S ORDER BY S.AVG_SAL
Типомрезультатаявляетсяlist < struct { integer DEPT_NO; decimal AVG_SAL } > .
Шаг 4. Выбрать значение атрибута DEPT _ NO из элемента списка SORTED _ DEPT _ AVG _ SAL с наименьшим значением AVG _ SAL (этот элемент стоит в списке первым).
FIRST (SORTED_DEPT_AVG_SAL ()).DEPT_NO
Если собрать запрос целиком, то мы получим следующую конструкцию:
FIRST (SELECT DEPT_NO,
AVG_SAL : avg (SELECT X.E.EMP_SAL FROM PARTITION X )
FROM (SELECT E FROM EMPLOYEES E
WHERE E.WORKS IS NOT nil) AS E
GROUP BY DEPT_NO : E.DEPT_NO
ORDER BY AVG_SAL).DEPT_NO