9.20. Агрегатные функции
Агрегатные функции получают единственный результат из набора входных значений. Встроенные агрегатные функции общего назначения перечислены в Таблице 9.55, а статистические агрегатные функции — в Таблице 9.56. Встроенные внутригрупповые сортирующие агрегатные функции перечислены в Таблице 9.57, встроенные внутригрупповые гипотезирующие — в Таблице 9.58. Группирующие операторы, тесно связанные с агрегатными функциями, перечислены в Таблице 9.59. Особенности синтаксиса агрегатных функцией разъясняются в Подразделе 4.2.7. За дополнительной вводной информацией обратитесь к Разделу 2.7.
Таблица 9.55. Агрегатные функции общего назначения
Функция | Типы аргумента | Тип результата | Частичный режим | Описание |
---|---|---|---|---|
array_agg( | любой тип не массива | массив элементов с типом аргумента | Нет | входные значения, включая NULL, объединяются в массив |
array_agg( | любой тип массива | тот же, что и тип аргумента | Нет | входные массивы собираются в массив большей размерности (они должны иметь одну размерность и не могут быть пустыми или равны NULL) |
avg( | smallint , int , bigint , real , double precision , numeric или interval | numeric для любых целочисленных аргументов, double precision для аргументов с плавающей точкой, в противном случае тип данных аргумента | Да | арифметическое среднее для всех входных значений, отличных от NULL |
bit_and( | smallint , int , bigint или bit | тот же, что и тип аргумента | Да | побитовое И для всех входных значений, не равных NULL, или NULL, если таких нет |
bit_or( | smallint , int , bigint или bit | тот же, что и тип аргумента | Да | побитовое ИЛИ для всех входных значений, не равных NULL, или NULL, если таких нет |
bool_and( | bool | bool | Да | true, если все входные значения равны true, и false в противном случае |
bool_or( | bool | bool | Да | true, если хотя бы одно входное значение равно true, и false в противном случае |
count(*) | bigint | Да | количество входных строк | |
count( | any | bigint | Да | количество входных строк, для которых значение выражения не равно NULL |
every( | bool | bool | Да | синоним bool_and |
json_agg( | any | json | Нет | агрегирует значения, включая NULL, в виде массива JSON |
jsonb_agg( | any | jsonb | Нет | агрегирует значения, включая NULL, в виде массива JSON |
json_object_agg( | (any, any) | json | Нет | агрегирует пары имя/значение в виде объекта JSON (NULL допускается в значениях, но не в именах) |
jsonb_object_agg( | (any, any) | jsonb | Нет | агрегирует пары имя/значение в виде объекта JSON (NULL допускается в значениях, но не в именах) |
max( | любой числовой, строковый, сетевой тип или тип даты/времени, либо массив этих типов | тот же, что и тип аргумента | Да | максимальное значение выражения среди всех входных данных, отличных от NULL |
min( | любой числовой, строковый, сетевой тип или тип даты/времени, либо массив этих типов | тот же, что и тип аргумента | Да | минимальное значение выражения среди всех входных данных, отличных от NULL |
string_agg( | (text , text ) или (bytea , bytea ) | тот же, что и типы аргументов | Нет | входные данные (исключая NULL) складываются в строку через заданный разделитель |
sum( | smallint , int , bigint , real , double precision , numeric , interval или money | bigint для аргументов smallint или int , numeric для аргументов bigint , и тип аргумента в остальных случаях | Да | сумма значений выражения по всем входным данным, отличным от NULL |
xmlagg( | xml | xml | Нет | соединение XML-значений, отличных от NULL (см. также Подраздел 9.14.1.7) |
Следует заметить, что за исключением count
, все эти функции возвращают NULL, если для них не была выбрана ни одна строка. В частности, функция sum
, не получив строк, возвращает NULL, а не 0, как можно было бы ожидать, и array_agg
в этом случае возвращает NULL, а не пустой массив. Если необходимо, подставить в результат 0 или пустой массив вместо NULL можно с помощью функции coalesce
.
Агрегатные функции, поддерживающие частичный режим, являются кандидатами на участие в различных оптимизациях, например, в параллельном агрегировании.
Примечание
Булевы агрегатные функции bool_and
и bool_or
соответствуют стандартным SQL-агрегатам every
и any
или some
. Что касается any
и some
, по стандарту их синтаксис допускает некоторую неоднозначность:
SELECT b1 = ANY((SELECT b2 FROM t2 ...)) FROM t1 ...;
Здесь ANY
можно рассматривать и как объявление подзапроса, и как агрегатную функцию, если этот подзапрос возвращает одну строку с булевым значением. Таким образом, этим агрегатным функциям нельзя было дать стандартные имена.
Примечание
Пользователи с опытом использования других СУБД SQL могут быть недовольны скоростью агрегатной функции count
, когда она применяется ко всей таблице. Подобный запрос:
SELECT count(*) FROM sometable;
потребует затрат в количестве, пропорциональном размеру таблицы: PostgreSQL придётся полностью просканировать либо всю таблицу, либо один из индексов, включающий все её строки.
Агрегатные функции array_agg
, json_agg
, jsonb_agg
, json_object_agg
, jsonb_object_agg
, string_agg
и xmlagg
так же, как и подобные пользовательские агрегатные функции, выдают разные по содержанию результаты в зависимости от порядка входных значений. По умолчанию порядок не определён, но его можно задать, дополнив вызов агрегатной функции предложением ORDER BY
, как описано в Подразделе 4.2.7. Обычно нужного результата также можно добиться, передав для агрегирования результат подзапроса с сортировкой. Например:
SELECT xmlagg(x) FROM (SELECT x FROM test ORDER BY y DESC) AS tab;
Но учтите, что этот подход может не работать, если на внешнем уровне запроса выполняется дополнительная обработка, например, соединение, так как при этом результат подзапроса может быть переупорядочен перед вычислением агрегатной функции.
В Таблице 9.56 перечислены агрегатные функции, обычно применяемые в статистическом анализе. (Они выделены просто для того, чтобы не загромождать список наиболее популярных агрегатных функций.) В их описании под N
подразумевается число входных строк, для которых входные выражения не равны NULL. Все эти функции возвращают NULL во всех случаях, когда вычисление бессмысленно, например, когда N
равно 0.
Таблица 9.56. Агрегатные функции для статистических вычислений
В Таблице 9.57 показаны некоторые агрегатные функции, использующие синтаксис сортирующих агрегатных функций. Иногда такие функции функциями называют функциями «обратного распределения».
Таблица 9.57. Сортирующие агрегатные функции
Все агрегатные функции, перечисленные в Таблице 9.57, игнорируют значения NULL при сортировке данных. Для функций, принимающих параметр дробь
, значение этого параметра должно быть от 0 до 1; в противном случае возникает ошибка. Однако если в этом параметре передаётся NULL, эти функции просто выдают NULL.
Все агрегатные функции, перечисленные в Таблице 9.58, связаны с одноимёнными оконными функциями, определёнными в Разделе 9.21. В каждом случае их результат — значение, которое вернула бы связанная оконная функция для «гипотетической» строки, полученной из аргументов
, если бы такая строка была добавлена в сортированную группу строк, которую образуют сортированные_аргументы
.
Таблица 9.58. Гипотезирующие агрегатные функции
Для всех этих гипотезирующих агрегатных функций непосредственные аргументы
должны соответствовать (по количеству и типу) сортированным_аргументам
. В отличие от встроенных агрегатных функций, они не являются строгими, то есть не отбрасывают входные строки, содержащие NULL. Значения NULL сортируются согласно правилу, указанному в предложении ORDER BY
.
Таблица 9.59. Операции группировки
Операции группировки применяются в сочетании с наборами группирования (см. Подраздел 7.2.4) для различения результирующих строк. Аргументы операции GROUPING
на самом деле не вычисляются, но они должны в точности соответствовать выражениям, заданным в предложении GROUP BY
на их уровне запроса. Биты назначаются справа налево (правый аргумент отражается в младшем бите); бит равен 0, если соответствующее выражение вошло в критерий группировки набора группирования, для которого сформирована строка результата, или 1 в противном случае. Например:
=>
SELECT * FROM items_sold;
make | model | sales -------+-------+------- Foo | GT | 10 Foo | Tour | 20 Bar | City | 15 Bar | Sport | 5 (4 rows)=>
SELECT make, model, GROUPING(make,model), sum(sales) FROM items_sold GROUP BY ROLLUP(make,model);
make | model | grouping | sum -------+-------+----------+----- Foo | GT | 0 | 10 Foo | Tour | 0 | 20 Bar | City | 0 | 15 Bar | Sport | 0 | 5 Foo | | 1 | 30 Bar | | 1 | 20 | | 3 | 50 (7 rows)