Получение данных из функций и процедур в PostgreSQL
Различные механизмы возврата наборов результатов в PostgreSQL требуют разных подходов к извлечению данных.
В статье Результирующие наборы данных в PostgreSQL описаны некоторые механизмы, которые PostgreSQL предоставляет для возврата результатов:
- RETURNS TABLE
- RETURNS SETOF
- INOUT REFCURSOR
Далее рассмотрим, как извлекать данные из функций и процедур, использующих эти механизмы.
1. Извлечение данных из функций с RETURNS TABLE
Функции, определённые с использованием RETURNS TABLE, можно напрямую запрашивать с помощью SQL.
Определение и особенности таких функций описаны в статье Результирующие наборы данных в PostgreSQL.
Пример функции:
CREATE OR REPLACE FUNCTION get_empl_by_id(v_EmpId INTEGER)
RETURNS TABLE
(
emp_id VARCHAR,
first_name VARCHAR,
last_name VARCHAR,
salary NUMERIC
)
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT emp_id, first_name, last_name, salary
FROM empl
WHERE emp_id = v_EmpId;
END;
$$;
Использование функции в SELECT
SELECT *
FROM get_empl_by_id(10);
Поскольку функция возвращает набор строк, её можно использовать во многих SQL-конструкциях.
Использование в CTE
WITH emp_data AS (
SELECT *
FROM get_empl_by_id(10)
)
SELECT *
FROM emp_data;
Использование в JOIN
SELECT e.*, d.department_name
FROM get_empl_by_id(10) e
JOIN departments d
ON e.emp_id = d.manager_id;
Это работает, потому что функция ведёт себя как табличное выражение.
2. Извлечение данных из функций с RETURNS SETOF
Функции, возвращающие SETOF, также формируют набор строк, однако структура результата определяется составным типом.
Более подробно об этом подходе и случаях его использования см. в статье Результирующие наборы данных в PostgreSQL.
Пример функции:
CREATE FUNCTION get_high_sal(min_salary NUMERIC)
RETURNS SETOF employee_info
LANGUAGE plpgsql
AS $$
BEGIN
RETURN QUERY
SELECT id, name, salary
FROM employee
WHERE salary >= min_salary;
END;
$$;
Данные можно извлекать тем же способом, что и при использовании RETURNS TABLE.
Использование в SELECT
SELECT *
FROM get_high_sal(5000);
Использование в JOIN
SELECT e.name, d.department_name
FROM get_high_sal(5000) e
JOIN departments d
ON e.id = d.manager_id;
Использование в подзапросах
SELECT name
FROM get_high_sal(5000)
WHERE salary > 10000;
3. Извлечение данных из процедур, возвращающих REFCURSOR
Процедуры, возвращающие параметры типа REFCURSOR, работают иначе.
Вместо прямого возврата наборов результатов они возвращают ссылки на открытые курсоры, которые необходимо явно считывать с помощью FETCH.
Подход к проектированию и реализации таких процедур описан в статье Результирующие наборы данных в PostgreSQL.
Метод 1 — Использование локальных переменных курсора
В этом подходе процедура вызывается из блока PL/pgSQL, а возвращаемые курсоры сохраняются в локальные переменные.
DO $$
DECLARE
v_cur1 refcursor;
v_cur2 refcursor;
v_rec record;
v_sal DECIMAL(10,2);
BEGIN
CALL fromora.get_empl_dept(1, v_sal, v_cur1, v_cur2);
RAISE NOTICE 'Salary: %', v_sal;
LOOP
FETCH v_cur1 INTO v_rec;
EXIT WHEN NOT FOUND;
RAISE NOTICE 'Employee: %', v_rec;
END LOOP;
LOOP
FETCH v_cur2 INTO v_rec;
EXIT WHEN NOT FOUND;
RAISE NOTICE 'Departments: %', v_rec;
END LOOP;
END;
$$;
Как вы можете видеть, данные из результирующих наборов обрабатываются построчно.
Метод 2 — Передача имён курсоров напрямую
Другой вариант заключается в передаче имён курсоров как литералов при вызове процедуры.
CALL fromora.get_empl_dept (1, NULL, 'rf1'::refcursor, 'rf2'::refcursor);
FETCH ALL FROM rf1;
--FETCH ALL FROM rf2;
В этом случае:
- процедура открывает курсоры с указанными именами
- вызывающая сторона получает результаты с помощью FETCH Этот метод часто используется в клиентских приложениях или скриптах.
Итог
Извлечение данных зависит от механизма, используемого для возврата набора результатов.
| Return mechanism | How to retrieve data |
|---|---|
| RETURNS TABLE | SELECT * FROM function() |
| RETURNS SETOF | SELECT * FROM function() |
| REFCURSOR | FETCH from returned cursor |
Функции, возвращающие RETURNS TABLE и RETURNS SETOF, напрямую интегрируются в SQL-запросы, тогда как REFCURSOR требует процедурного подхода для извлечения данных.
Подробнее о том, как реализованы эти механизмы и когда их следует использовать, см. в статье Результирующие наборы данных в PostgreSQL.