Групповые функции FIRST и LAST

Очень часто при выборке данных появляется задача определения значения первой записи в заданной подгруппе для его дальнейшего использования, например, в качестве параметра. Или еще один распространенный случай: выбрать первую запись из отсортированной выборки. Эту задачу можно решить с помощью псевдостолбца ROWNUM, но тогда потребуется использование вложенного подзапроса, т.к. сначала необходимо выбираемые данные отсортировать. В таких случаях наиболее эффективным решением будет использование групповых функций FIRST и LAST.

Функции FIRST и LAST позволяют ранжировать записи выборки и выполнять дальнейшие вычисления над записями только наибольшего или наименьшего ранга. Данные функции аналогичны друг другу с той лишь разницей, что обрабатывается первая или последняя запись выборки соответственно. Общий вид использования на примере функции FIRST:

aggregate_function KEEP (DENSE_RANK {FIRST | LAST}
ORDER BY expr [ DESC | ASC ] [NULLS { FIRST | LAST }]
[, expr [ DESC | ASC ] [NULLS { FIRST | LAST }]])+
[OVER query_partitioning_clause]

 

Возможно использование в двух режимах – агрегирующем и аналитическом. В обоих случаях все значения в рамках своей подгруппы ранжируются от”первого” до “последнего” с учетом заданной сортировки. При этом, несколько значений могут получить одинаковый ранг. Далее к полученному набору одноранговых значений применяется заданная агрегирующая функция. В качестве аргумента функции допускается значение любого числового типа, или значение, которое может быть неявно преобразовано к числовому. В качестве результата возвращается числовое значение.

Групповые функции, допустимые к использованию с FIRST и LAST: MIN, MAX, SUM, AVG, COUNT, VARIANCE, STDDEV. Они производят вычисления над набором значений, получивших ранг “первый” (в случае FIRST) или “последний” (в случае LAST). Если заданный ранг получило только одно значение, вычисления производятся над множеством из одного элемента.

Элементы вызова

KEEP – ключевое слово, выполняющая семантическую задачу. Показывает, что групповая функция будет работать только с записями наибольшего/наименьшего ранга.

DENSE_RANK FIRST/DENSE_RANK LAST – определяет ранг записей (“первый”/”последний”), которые будут переданы групповой функции для вычислений.

OVER – аналитический режим. В этом случае, в качестве обрабатывающей групповой функции используется аналитическая функция, а в конструкции OVER допустима единственная конструкция PARTITION BY.

Пример использования в режиме группировки

Возьмем стандартный пример БД отдела кадров предприятия (схема HR) и рассмотрим применение FIRST/LAST на примере выборки минимальной зарплаты сотрудников с наименьшими комиссионными и максимальной зарплаты сотрудников с наибольшими комиссионными по каждому отделу.

SELECT
    department_id,
    MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct) "Worst",
    MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct) "Best"
FROM employees
GROUP BY department_id
ORDER BY department_id, "Worst", "Best";

 

DEPARTMENT_ID Worst Best
10
4400
4400
20
6000
13000
30
2500
11000
40
6500
6500
50
2100
8200
60
4200
9000
70
10000
10000
80
6100
14000
90
17000
24000
100
6900
12000
110
8300
12000
7000
7000

 

Пример работы в аналитическом режиме

Теперь выполним расчет предыдущего примера, но сформируем информацию для каждого сотрудника по отделам.

SELECT
last_name,
department_id,
salary,
MIN(salary) KEEP (DENSE_RANK FIRST ORDER BY commission_pct) OVER (PARTITION BY department_id) "Worst",
MAX(salary) KEEP (DENSE_RANK LAST ORDER BY commission_pct) OVER (PARTITION BY department_id) "Best"
FROM employees
ORDER BY department_id, salary;

 

LAST_NAME DEPARTMENT_ID SALARY Worst Best
Whalen
10
4400
4400
4400
Fay
20
6000
6000
13000
Hartstein
20
13000
6000
13000
Colmenares
30
2500
2500
11000
Himuro
30
2600
2500
11000
Tobias
30
2800
2500
11000
De Haan
90
17000
17000
24000
King
90
24000
17000
24000
Popp
100
6900
6900
12000
Sciarra
100
7700
6900
12000
Urman
100
7800
6900
12000
Chen
100
8200
6900
12000
Faviet
100
9000
6900
12000
Greenberg
100
12000
6900
12000
Gietz
110
8300
8300
12000
Higgins
110
12000
8300
12000
Grant
7000
7000
7000

 

Close Menu