问题
I'm dynamically building a query in a plpgsql function that accepts a source table as an incoming variable. I want to return the results of the built SELECT
statement, which performs aggregations on the given table, and returns results of that table.
However, at the moment I'm getting the following error:
********** Error **********
ERROR: a column definition list is required for functions returning "record" SQL state: 42601
So it looks like I need to define column types of the record rows I want to return.
I found this answer where you can bypass table type declaration by providing the table to which the resulting row will match.
RETURNS SETOF some_existing_table
However, in my case, since the table whose column types I want to match is passed to the function, I don't know the table until I can manipulate the variables passed (after DECLARE
/BEGIN
).
Ideally, I want to return the query results (multiple rows) of the aggregation query I build within the function. Is there a way to define result row return types based on a known table dynamically within the function?
回答1:
Is there a way to define result row return types based on a known table dynamically within the function?
If by "based on a known table" you mean "exactly like a known table", then yes.
SQL is a strictly typed language and functions must be created with a well defined return type. You can fall back to anonymous records like you obviously did (with RETURNS SETOF record
), but then you are required to add a column definition list for every call, like the error message tells you. Something like:
SELECT *
FROM my_function('foo') AS foo (
colum_name1 integer -- name and data type for every column
, colum_name2 text
, colum_name3 real);
And this is hardly dynamic.
Your question leaves room for interpretation, but "based on a known table" would indicate that a polymorphic function might do the trick. The return type can be based on any registered row type dynamically, and there is one for every table in the system automatically. Barebone code example:
CREATE OR REPLACE FUNCTION my_function(_rowtype anyelement)
RETURNS SETOF anyelement AS
$func$
BEGIN
RETURN QUERY EXECUTE format(
'SELECT * FROM %s LIMIT 10'
, pg_typeof(_rowtype) -- pg_typeof() returns regtype, quoted where necessary
);
END
$func$ LANGUAGE plpgsql;
Call:
SELECT * FROM my_function(NULL::my_table);
Detailed instructions in this related answer (look to the last chapter "Various complete table types"):
- Refactor a PL/pgSQL function to return the output of various SELECT queries
来源:https://stackoverflow.com/questions/36668165/dynamically-define-returning-row-types-based-on-a-passed-given-table-in-plpgsql