×
Мы обрабатываем cookies, чтобы сделать наш сайт удобнее и персонализированнее для вас. Подробнее: политика использования «cookies» и «политики конфиденциальности».

Для самостоятельной настройки ознакомьтесь с инструкцией

Дополнительные настройки cookies в браузерах

Файлы cookie автоматически загружаются в ваш браузер при посещении веб-сайта. У вас есть возможность управлять этими файлами. Если Вы не согласны с использованием файлов cookies, запретите их сохранение на своём устройстве, удалите уже имеющиеся файлы cookies через настройки браузера или прекратите использование сайта.

При отключении обработки cookie наш сайт продолжит функционировать, однако будут использоваться исключительно необходимые технические файлы, без которых работа ресурса невозможна.

Инструкция по отключению cookies
Принять
Настроить
Отклонить

ДОКУМЕНТАЦИЯ

Выберите версию, форк и язык для СУБД Digital Q.DataBase, чтобы прочитать или скачать всю документацию.
Техподдержка
Документация
Диасофт
Авторские права © 2016–2025 ООО "Диасофт Экосистема"
Скачать всю документацию:

1.3.5. Оконные функции

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

Ниже приведен пример, демонстрирующий сравнение заработной платы каждого сотрудника со средней заработной платой в соответствующем отделе:

SELECT depname, empno, salary, avg(salary) OVER (PARTITION BY depname) FROM empsalary;

  depname  | empno | salary |          avg
-----------+-------+--------+-----------------------
 develop   |    11 |   5200 | 5020. 0000000000000000
 develop   |     7 |   4200 | 5020. 0000000000000000
 develop   |     9 |   4500 | 5020. 0000000000000000
 develop   |     8 |   6000 | 5020. 0000000000000000
 develop   |    10 |   5200 | 5020. 0000000000000000
 personnel |     5 |   3500 | 3700. 0000000000000000
 personnel |     2 |   3900 | 3700. 0000000000000000
 sales     |     3 |   4800 | 4866. 6666666666666667
 sales     |     1 |   5000 | 4866. 6666666666666667
 sales     |     4 |   4800 | 4866. 6666666666666667
(10 строк)

Первые три столбца вывода получены непосредственно из таблицы empsalary, при этом для каждой строки таблицы формируется одна строка вывода. В четвертом столбце представлено среднее значение, вычисленное по всем строкам таблицы, имеющим то же значение depname , что и текущая строка. (Фактически это та же функция, что и обычный (не оконный) агрегат avg , однако OVER предложение предписывает обрабатывать ее как оконную функцию с вычислением в пределах рамки окна.)

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

Порядком обработки строк в оконных функциях можно управлять с помощью предложения ORDER BY внутри OVER. (Порядок обработки ORDER BY оконной функцией даже не обязан совпадать с порядком вывода строк.) Ниже приведен пример:

SELECT depname, empno, salary,
       rank() OVER (PARTITION BY depname ORDER BY salary DESC)
FROM empsalary;

  depname  | empno | salary | rank
-----------+-------+--------+------
 develop   |     8 |   6000 |    1
 develop   |    10 |   5200 |    2
 develop   |    11 |   5200 |    2
 develop   |     9 |   4500 |    4
 develop   |     7 |   4200 |    5
 personnel |     2 |   3900 |    1
 personnel |     5 |   3500 |    2
 sales     |     1 |   5000 |    1
 sales     |     4 |   4800 |    2
 sales     |     3 |   4800 |    2
(10 rows)

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

Строки, обрабатываемые оконной функцией, представляют собой строки «виртуальной таблицы,» сформированной FROM предложением запроса и отфильтрованной его WHERE, GROUP BYи HAVING предложениями, если таковые имеются. Например, строка, удаленная из-за несоответствия WHERE условию, не будет видна ни одной оконной функции. Запрос может содержать несколько оконных функций, сегментирующих данные различными способами с использованием разных OVER предложения, однако все они воздействуют на один и тот же набор строк, определяемый данной виртуальной таблицей.

Ранее было показано, что ORDER BY может быть опущено, если порядок следования строк не имеет значения. Также допускается исключение PARTITION BY, в результате чего создается единственная секция, включающая все строки.

С оконными функциями связано еще одно важное понятие: для каждой строки в пределах ее секции определяется набор строк, называемый Рамка окна. Некоторые оконные функции обрабатывают только строки рамки окна, а не всей секции. По умолчанию, если ORDER BY задано, то рамка включает все строки от начала секции до текущей включительно, а также любые последующие строки, эквивалентные текущей согласно ORDER BY предложению. Если ORDER BY не указано, рамка по умолчанию включает все строки в секции. [5] Ниже приведен пример использования функции sum:

SELECT salary, sum(salary) OVER () FROM empsalary;
 salary |  sum
--------+-------
   5200 | 47100
   5000 | 47100
   3500 | 47100
   4800 | 47100
   3900 | 47100
   4200 | 47100
   4500 | 47100
   4800 | 47100
   6000 | 47100
   5200 | 47100
(10 rows)

В приведенном выше примере, так как ORDER BY в OVER Предложение не используется, рамка окна совпадает с секцией, которая при отсутствии PARTITION BY представляет собой всю таблицу; иными словами, каждое значение sum вычисляется по всей таблице, поэтому для каждой строки результата получается одно и то же значение. Однако если добавить ORDER BY предложение, мы получим совершенно иные результаты:

SELECT salary, sum(salary) OVER (ORDER BY salary) FROM empsalary;
 salary |  sum
--------+-------
   3500 |  3500
   3900 |  7400
   4200 | 11600
   4500 | 16100
   4800 | 25700
   4800 | 25700
   5000 | 30700
   5200 | 41100
   5200 | 41100
   6000 | 47100
(10 rows)

Здесь сумма накапливается от первой (наименьшей) заработной платы до текущей строки, включая все дубликаты текущего значения (обратите внимание на результаты для одинаковых значений заработной платы).

Оконные функции допускаются только в SELECT списке выбора и в ORDER BY предложении запроса. Их использование запрещено в других частях, таких как GROUP BY, HAVING и WHERE предложения. Это обусловлено тем, что их логическое выполнение происходит после обработки данных предложений. Кроме того, оконные функции выполняются после агрегатных функций, не являющихся оконными. Следовательно, допускается вызов агрегатной функции в аргументах оконной функции, но не наоборот.

При необходимости фильтрации или группировки строк после выполнения оконных вычислений можно использовать подзапрос. Например:

SELECT depname, empno, salary, enroll_date
FROM
  (SELECT depname, empno, salary, enroll_date,
          rank() OVER (PARTITION BY depname ORDER BY salary DESC, empno) AS pos
     FROM empsalary
  ) AS ss
WHERE pos < 3;

Приведенный выше запрос выводит только те строки внутреннего запроса, для которых значение rank меньше 3.

Если запрос содержит несколько оконных функций, каждую из них можно определить с помощью отдельного OVER Предложение, однако такой подход ведет к дублированию кода и возникновению ошибок в случаях, когда идентичное поведение окна требуется для нескольких функций. Вместо этого каждое определение поведения окна может быть именовано в WINDOW Предложение и затем указано в OVER. Например:

SELECT sum(salary) OVER w, avg(salary) OVER w
  FROM empsalary
  WINDOW w AS (PARTITION BY depname ORDER BY salary DESC);

Подробные сведения об оконных функциях приведены в Раздел 2.1.2.8, Раздел 2.6.22, Раздел 2.4.2.5, а также на SELECT странице справочного руководства.



[5] Предусмотрены и другие способы определения рамки окна, однако в данном руководстве они не рассматриваются. См. Раздел 2.1.2.8 для получения подробных сведений.

Наверх
свяжитесь
с нами
контакты
Для прямой связи с нами вы можете использовать контакты ниже, либо оставить заявку через форму обратной связи, и мы обязательно свяжемся с вами

*поля обязательные к заполнению