Dynamically define returning row types based on a passed given table in plpgsql?

冷暖自知 提交于 2020-01-03 03:32:06

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!