Обзор
Я использую PostgreSQL 9.1.14, и я пытаюсь передать результаты функции в другую функцию. Общая идея (с учетом минимального примера) заключается в том, что мы можем написать:
select * from (select * from foo ...)
и мы можем абстрагировать подвыбор в функции и выбрать из него:
create function foos()
returns setof foo
language sql as $$
select * from foo ...
$$;
select * from foos()
Есть ли способ абстрагироваться на один уровень дальше, чтобы иметь возможность делать что-то вроде этого (я знаю, что функции не могут иметь аргументы с типами setof):
create function more_foos( some_foos setof foo )
language sql as $$
select * from some_foos ... -- or unnest(some_foos), or ???
$$:
select * from more_foos(foos())
Минимальный пример и предпринятые обходные методы
Я использую PostgreSQL 9.1.14. Вот минимальный пример:
-- 1. create a table x with three rows
drop table if exists x cascade;
create table if not exists x (id int, name text);
insert into x values (1,'a'), (2,'b'), (3,'c');
-- 2. xs() is a function with type `setof x`
create or replace function xs()
returns setof x
language sql as $$
select * from x
$$;
-- 3. xxs() should return the context of x, too
-- Ideally the argument would be a `setof x`,
-- but that not allowed (see below).
create or replace function xxs(x[])
returns setof x
language sql as $$
select x.* from x
join unnest($1) y
on x.id = y.id
$$;
Когда я загружаю этот код, я получаю ожидаемый вывод для определений таблиц, и я могу позвонить и выбрать из xs()
, как я ожидал. Но когда я пытаюсь передать результат xs()
на xxs()
, я получаю сообщение об ошибке "Функция xxs (x) не существует":
db=> \i test.sql
DROP TABLE
CREATE TABLE
INSERT 0 3
CREATE FUNCTION
CREATE FUNCTION
db=> select * from xs();
1 | a
2 | b
3 | c
db=> select * from xxs(xs());
ERROR: function xxs(x) does not exist
LINE 1: select * from xxs(xs());
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
Я немного смущен о "функции xxs (x) не существует"; так как возвращаемый тип xs()
был setof x
, я ожидал, что его тип возврата будет setof x
(или, может быть, x[]
), а не x
. После жалоб на тип, я могу перейти к одному из следующих, но хотя с любым определением я могу select xxs(xs());
, я не могу select * from xxs(xs());
.
create or replace function xxs( x )
returns setof x
language sql as $$
select x.* from x
join unnest(array[$1]) y -- unnest(array[...]) seems pretty bad
on x.id = y.id
$$;
create or replace function xxs( x )
returns setof x
language sql as $$
select * from x
where x.id in ($1.id)
$$;
db=> select xxs(xs());
(1,a)
(2,b)
(3,c)
db=> select * from xxs(xs());
ERROR: set-valued function called in context that cannot accept a set
Резюме
Каков правильный способ передачи результатов функции возвращающего множество в другую функцию? (Я заметил, что создать функцию... xxs (setof)... приводит к ошибке: ОШИБКА: функции не могут принимать заданные аргументы, поэтому ответ не будет буквально передаваться набор строк из одной функции в другую.)