Подтвердить что ты не робот

Функция PostgreSQL или хранимая процедура, которая выводит несколько столбцов?

Вот что я в идеале хочу. Представьте, что у меня есть таблица со строкой A.

Я хочу сделать:

SELECT A, func(A) FROM table

а для вывода - 4 столбца.

Есть ли способ сделать это? Я видел вещи на пользовательских типах или что-то еще, что позволило вам получить результат, который будет выглядеть как

А, (В, С, D)

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

Есть ли что-нибудь, что может сделать что-то вроде этого?

4b9b3361

Ответ 1

Если функция func возвращает только 1 строку с тремя значениями, например:

CREATE OR REPLACE FUNCTION func
(
    input_val       integer,
    OUT output_val1 integer,
    OUT output_val2 integer,
    OUT output_val3 integer
)
AS $$
BEGIN
  output_val1 := input_val + 1;
  output_val2 := input_val + 2;
  output_val3 := input_val + 3;
END;
$$ LANGUAGE plpgsql;

а затем выполните SELECT a, func(a) FROM table1, вы получите:

a       | func
integer | record
========|==========
1       | (2, 3, 4)
2       | (3, 4, 5)
3       | (4, 5, 6)

но если вы выполните:

SELECT a, (f).output_val1, (f).output_val2, (f).output_val3
FROM (SELECT a, func(a) AS f FROM table1) AS x

вы получите:

a       | output_val1 | output_val2 | output_val3
integer | integer     | integer     | integer
========|=============|=============|=============
1       | 2           | 3           | 4
2       | 3           | 4           | 5
3       | 4           | 5           | 6

или, используя CTE (Общие выражения таблицы), если вы выполните:

WITH temp AS (SELECT a, func(a) AS f FROM table1)
SELECT a, (f).output_val1, (f).output_val2, (f).output_val3 FROM temp

вы также получите:

a       | output_val1 | output_val2 | output_val3
integer | integer     | integer     | integer
========|=============|=============|=============
1       | 2           | 3           | 4
2       | 3           | 4           | 5
3       | 4           | 5           | 6

Примечание. Вы можете также использовать следующие запросы для получения тех же результатов:

SELECT a, (f).*
FROM (SELECT a, func(a) AS f FROM table1) AS x

или

WITH temp AS (SELECT a, func(a) AS f FROM table1)
SELECT a, (f).* FROM temp

Ответ 2

Я согласен с ответом на bambam, но хотел бы отметить, что JackPDouglas более сжатый синтаксис SELECT a, (func(a)).* FROM table1, из моих тестов, фактически выполнит эту функцию один раз для каждого возвращаемого столбца, тогда как выражение CTE будет выполнять эту функцию только один раз. Таким образом, выражение CTE является предпочтительным, если функция занимает много времени.

Ответ 3

Если функция всегда возвращает 3 столбца, вы можете сделать что-то вроде этого:

CREATE TYPE sometype AS (b INT, c TEXT, d TEXT);

CREATE OR REPLACE FUNCTION func(a TEXT) RETURNS SETOF sometype AS $$
BEGIN
  RETURN QUERY EXECUTE 'SELECT b, c, d FROM ' || a;
END;
$$ LANGUAGE plpgsql;

SELECT a, (f).b, (f).c, (f).d 
FROM (SELECT a, func(a) AS f FROM table) x;

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

CREATE VIEW v AS 
SELECT 'tab1' AS a, b, c, d FROM tab1 WHERE 'tab1' IN (SELECT a FROM table)
UNION
SELECT 'tab2' AS a, b, c, d FROM tab2 WHERE 'tab2' IN (SELECT a FROM table)
UNION
SELECT 'tab3' AS a, b, c, d FROM tab3 WHERE 'tab3' IN (SELECT a FROM table);

то это просто a SELECT * FROM v. Но опять-таки это выглядит как "Наследование" .

Ответ 4

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

http://www.postgresql.org/docs/9.0/static/plpgsql-declarations.html

И о типах возврата:

http://www.postgresql.org/docs/9.0/static/xfunc-sql.html#XFUNC-OUTPUT-PARAMETERS

Если вы хотите вернуть несколько записей с несколькими столбцами, сначала проверьте и проверьте, нужно ли вам использовать хранимую процедуру для этого. Это может быть вариант просто использовать VIEW (и запросить его с предложением WHERE). Если это не очень хороший вариант, есть возможность вернуть TABLE из хранимой процедуры в версии 9.0.