Функция PostgreSQL или хранимая процедура, которая выводит несколько столбцов? - PullRequest
12 голосов
/ 28 марта 2011

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

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

SELECT A, func(A) FROM table

и для вывода, скажем, 4 столбца.

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

А, (В, С, D)

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

Есть что-нибудь, что может сделать что-то подобное?

Ответы [ 4 ]

17 голосов
/ 07 мая 2011

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

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
6 голосов
/ 03 июня 2011

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

2 голосов
/ 29 марта 2011

Если функция всегда возвращает 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);

тогда это просто SELECT * FROM v.Но, опять же, похоже, что Наследование можно использовать.

0 голосов
/ 29 марта 2011

Я думаю, вы захотите вернуть одну запись с несколькими столбцами?В этом случае вы можете использовать тип возврата 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.

...