Функции на языке запросов (SQL)

SQL-функция выполняет произвольный набор команд на языке SQL, разделённых точкой с запятой, и возвращает результат последнего запроса в списке. Помимо запросов SELECT, эти команды могут включать запросы, изменяющие данные (INSERT, UPDATE и DELETE и MERGE), а также другие SQL-команды.

circle-exclamation

Последней командой должна быть SELECT или команда с предложением RETURNING, возвращающая результат с типом возврата функции. В простом случае будет возвращена первая строка результата последнего запроса. Если последний запрос не вернёт ни одной строки, то будет возвращено значение NULL.

circle-info

Помните, что если отсутствует предложение ORDER BY, то порядок строк в результате не гарантирован, а значит ответ функции на тех же данных может меняться.

Функции можно разделить по типу возвращаемого значения:

  • Без возврата значений;

  • Возвращающие единственную запись базового типа, составного типа или типа record;

  • C выходными параметрами;

  • Возвращающие множество (SETOF) записей базового типа, составного типа или типа record;

  • Возвращающие таблицу (TABLE).

Далее рассмотрим все варианты SQL-функций. А подробный материал по функциям на языке SQL можно найти по ссылкеarrow-up-right.

Аргументы функции

К аргументам SQL-функции можно обращаться по именам или индексу.

Объявив аргумент с именем, это имя можно использовать в теле функции:

CREATE OR REPLACE FUNCTION template.user_get_full_name(in_user_id smallint)
  RETURNS character varying AS
$BODY$
  SELECT
    user_full_name
  FROM
    template.user_info
  WHERE
    user_id = in_user_id;
$BODY$
  LANGUAGE sql;
circle-info

Если имя аргумента совпадает с именем какого-либо столбца в текущей SQL-команде внутри функции, имя столбца всегда будет иметь приоритет. Чтобы избежать неоднозначности, дополните имя аргумента именем самой функции: имя_функции.имя_аргумента.

При обращении к аргументу по индексу используется запись вида $n. Нумерация аргументов начинается с единицы: $1 обозначает первый аргумент, $2 - второй и т. д. Обращение по номеру будет работать, и когда аргументам назначены имена.

Без возврата значений

Если нужна SQL-функция, выполняющая действие, но не возвращающая полезное значение, можно объявить её как возвращающую тип void.

Например, эта функция удаляет черновые записи клиентов из таблицы:

Одна строка

Базовый тип

Простейшая возможная функция SQL не имеет аргументов и возвращает базовый тип. Такая функция возвращает таблицу с одним столбцом и одной строкой.

Например, функция ниже возвращает идентификатор типа smallint:

circle-info

Если последняя команда SELECT или RETURNING в SQL-функции возвращает результат типа отличного от возвращаемого типа функции, то PostgreSQL автоматически приведёт возвращаемое значение к нужному типу, если это возможно с применением приведения присваивания или неявным образом. В противном случае должно быть явное приведение.

Составной тип

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

Например, функция получения настроек SMTP-сервера будет возвращать одну строку типа template.settings:

Тогда в ответе получим:

circle-info

Составной тип возвращаемого значения накладывает ограничение: тип, количество и порядок столбцов ответа должны совпадать с описанием столбцов таблицы.

Запись (тип record)

Если составной тип не подходит в качестве типа возвращаемого значения, так как содержит избыточные столбцы, то можно объявить функцию, возвращающую тип record. Такие переменные не имеют предопределённой структуры. Количество и тип столбцов результата будет равно количеству полей последнего запроса в теле функции.

Например, функция получения настроек SMTP-сервера из предыдущего примера будет переписана следующим образом:

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

Ответ функции будет иметь вид:

C выходными параметрами

Альтернативный способ описать результаты функции - определить её с выходными параметрами. Например:

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

В ответ получим:

Множество (SETOF)

Можно объявить SQL-функцию как возвращающую множество. В этом случае будут возвращены все строки результата последнего запроса.

Когда SQL-функция объявляется как возвращающая SETOFнекий_тип, конечный запрос функции выполняется до завершения и каждая строка выводится как элемент результирующего множества.

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

Множество базового типа

Функция может возвращать множество простого типа, тогда в ответе будет таблица с одним столбцом.

В ответ получим:

Множество составного типа

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

В ответ получим:

circle-info

Составной тип возвращаемого значения накладывает ограничение: тип, количество и порядок столбцов ответа должны совпадать с описанием столбцов таблицы.

Множество записей

Также возможно выдать несколько строк со столбцами, определяемыми выходными параметрами. Для этого необходимо указать функцию возвращающую SETOF record.

Например, функция возвращающая список идентификаторов товаров и их стоимость:

В ответ получим таблицу:

Тип record позволяет использовать динамическую структуру выходной таблицы.

TABLE

Есть ещё один способ объявить функцию, возвращающую множества, - использовать синтаксис RETURNS TABLE(столбцы). Это равнозначно использованию одного или нескольких параметров OUT с объявлением функции, возвращающей SETOF record.

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

Запись RETURNS TABLE не позволяет явно указывать OUT и INOUT для параметров - все выходные столбцы необходимо записать в списке TABLE.

Last updated