Результирующие наборы данных в PostgreSQL
В отличие от таких Баз Данных, как Microsoft SQL Server или Sybase Adaptive Server Enterprise, PostgreSQL не позволяет процедурам напрямую возвращать наборы результатов так же, как это делает обычный оператор SELECT.
Однако PostgreSQL предоставляет несколько механизмов для возврата наборов строк.
В настоящее время Конвертум Мастер поддерживает следующие подходы:
- RETURNS TABLE (вариант по умолчанию)
- RETURNS SETOF
- INOUT REFCURSOR
Последние два варианта требуют дополнительной настройки инструмента. Более подробную информацию о конфигурации можно найти в статье: Настройка параметра преобразования результирующих наборов для PostgreSQL.
Далее рассмотрим механизмы, используемые для возврата наборов результатов в PostgreSQL.
1. RETURNS TABLE
CREATE OR REPLACE FUNCTION get_empl_by_id(v_EmpId INTEGER)
RETURNS TABLE
(
emp_id VARCHAR,
first_name VARCHAR,
last_name VARCHAR,
salary VARCHAR
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
empl.emp_id,
empl.first_name,
empl.last_name,
empl.salary
FROM empl
WHERE empl.emp_id = v_EmpId;
END;
$$;
Этот вариант удобен, когда функция должна возвращать результат, аналогичный обычному запросу SELECT.
Преимущества:
- обеспечивает хорошую читаемость кода
- возвращает набор строк, который ведёт себя как обычная таблица
- функцию можно использовать напрямую в:
- SELECT
- CTE (WITH)
- подзапросах
- других функциях
- не требуется объявлять отдельные OUT-параметры, поскольку выходные столбцы задаются напрямую в конструкции RETURNS TABLE
Функции, определённые таким образом, естественно интегрируются в SQL-запросы.
Примеры вызова таких функций и получения результатов описаны в статье Получение данных из функций и процедур в PostgreSQL.
2. RETURNS SETOF (составной тип)
CREATE TYPE employee_info AS (
emp_id INT,
name TEXT,
salary NUMERIC
);
CREATE FUNCTION get_high_sal (min_salary NUMERIC)
RETURNS SETOF employee_info
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT
id,
name,
salary
FROM empl
WHERE salary >= min_salary;
END;
$$;
В нашем инструменте этот подход реализуется через составной тип, который создаётся перед самой функцией.
Такие функции возвращают набор строк и также могут использоваться напрямую в:
- SELECT
- CTE (WITH)
- подзапросах
- других функциях
Однако этот подход, как правило, менее читаем и требует предварительного создания составного типа.
Примеры выполнения запросов к функциям, возвращающим значения SETOF, приведены в статье Получение данных из функций и процедур в PostgreSQL.
Ограничения RETURNS TABLE и RETURNS SETOF
Оба подхода имеют ряд общих ограничений:
- структура возвращаемого набора результатов должна быть заранее определена, поэтому динамическое изменение набора возвращаемых столбцов не поддерживается
- весь набор результатов формируется и возвращается целиком
- для больших объёмов данных это может негативно сказаться на производительности
Примечание:
Не допускается использование явных параметров OUT или INOUT совместно с конструкцией RETURNS TABLE. Все выходные столбцы должны быть определены исключительно в секции TABLE.
3. INOUT REFCURSOR
Если требуется возвращать несколько наборов результатов или получать данные по частям (построчно/порционно), можно использовать параметры типа REFCURSOR.
Наш инструмент поддержки конвертации преобразует такую логику в процедуру, использующую параметры REFCURSOR в качестве INOUT-аргументов.
CREATE OR REPLACE PROCEDURE fromora.get_empl_dept(
v_EmpId INTEGER,
INOUT v_MinSalary DECIMAL(10,2),
INOUT SWV_RefCur refcursor DEFAULT NULL,
INOUT SWV_RefCur2 refcursor DEFAULT NULL
)
LANGUAGE plpgsql
AS $$
BEGIN
-- get information about a specific employee
OPEN SWV_RefCur FOR
SELECT emp_id, name, salary
FROM fromora.empl
WHERE emp_id = v_EmpId;
-- fill the output parameter
SELECT salary INTO v_MinSalary
FROM empl
WHERE emp_id = v_EmpId
UNION ALL
SELECT v_MinSalary;
-- get the list of departments
OPEN SWV_RefCur2 FOR
SELECT dept_id, location, region
FROM fromora.dept;
END;
$$;
Преимущества использования REFCURSOR:
- в рамках одной процедуры можно открывать несколько курсоров
- позволяет возвращать несколько независимых наборов результатов
- структура результирующего набора может определяться динамически
- поддерживает поэтапное извлечение данных с помощью FETCH
Ограничения:
- более сложный синтаксис
- курсоры нельзя использовать напрямую в SQL-запросах
- большое количество крупных курсоров может потреблять значительный объём памяти
- построчная обработка (FETCH) обычно медленнее, чем наборный SELECT
REFCURSOR — это ссылка на открытый курсор, который указывает на результат запроса, хранящийся на сервере. Для доступа к данным его необходимо явно извлечь с помощью FETCH.
Подробные примеры вызова таких процедур и получения данных из возвращаемых курсоров приведены в статье Получение данных из функций и процедур в PostgreSQL.