Ошибка синтаксиса в процессе создания агрегированных


Попытка создать агрегатную функцию:

create aggregate min (my_type) (
    sfunc = least,
    stype = my_type
);
ERROR:  syntax error at or near "least"
LINE 2:     sfunc = least,
                    ^

Что я упускаю?

Хотя руководство вызывает least функцию:

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

Я не могу его найти:

dfS least
                       List of functions
 Schema | Name | Result data type | Argument data types | Type 
--------+------+------------------+---------------------+------
(0 rows)
2 3

2 ответа:

LEAST и GREATEST не являются реальными функциями; внутренне они разбираются как MinMaxExpr (см. src/include/nodes/primnodes.h).

Вы можете достичь желаемого с помощью такой универсальной функции:

CREATE FUNCTION my_least(anyelement, anyelement) RETURNS anyelement
   LANGUAGE sql IMMUTABLE CALLED ON NULL INPUT
   AS 'SELECT LEAST($1, $2)';

(Спасибо Эрвину Брандштеттеру за CALLED ON NULL INPUT и идею использовать LEAST.)

Тогда вы можете создать свой агрегат как

CREATE AGGREGATE min(my_type) (sfunc = my_least, stype = my_type);

Это будет работать только в том случае, если существуют функции сравнения для my_type, в противном случае вам придется придумать другую функцию my_least.

Как CASE, COALESCE и еще NULLIF, GREATEST и LEAST перечислены в главе условные выражения. Эти конструкции SQL не реализуются как функции .. как @Laurenz обеспечил в то же время.

Руководство советует:

Совет: Если ваши потребности выходят за рамки возможностей этих условных выражения, вы можете рассмотреть возможность записи хранимой процедуры в более выразительное Программирование язык.

Терминология здесь тоже немного не та, поскольку Postgres не поддерживает истинные "хранимые процедуры", а только функции. (Именно поэтому существуетоткрытый пункт TODO "реализация хранимых процедур".)

Эту страницу руководства можно было бы заострить, чтобы избежать путаницы ...

@Laurenz также привел пример. Я бы просто использовал LEAST в функции, чтобы получить идентичную функциональность:

CREATE FUNCTION f_least(anyelement, anyelement)
  RETURNS anyelement LANGUAGE sql IMMUTABLE AS
'SELECT LEAST($1, $2)';

Do нет сделайте это STRICT, чтобы это было бы неверно. LEAST(1, NULL) возвращает 1, а не NULL.

Даже если бы STRICT был правильным, я бы не стал его использовать, потому что он может предотвратить подстановку функций.

Обратите внимание, что эта функция ограничена ровно двумя параметрами, в то время как LEAST принимает любое число параметров. Вы можете перегрузить функцию, чтобы покрыть 3, 4 и т. д. входной параметр. Или вы можете написать функцию VARIADIC Для 100 параметров.