質問

I want to create a function that returns rows from a view created from a unknown table(s):

    CREATE OR REPLACE FUNCTION tt_query(text, timestamp without time zone)
      RETURNS SETOF record AS
    $$
    DECLARE

    orig_name ALIAS FOR $1;
    data_tt ALIAS FOR $2;

    BEGIN

    [...]

    EXECUTE 'create OR REPLACE TEMP view temp as 
    select * 
    from  '
    ||orig_name 
    ||' where trigger_changed >'
    ||quote_literal(data_tt)
    ||' ORDER BY trigger_changed DESC';

    [...]--other work on view temp

    --NOW I WANT RETURN THE ROW OF view temp
    END;
    $$
    LANGUAGE plpgsql VOLATILE

ok I have think (with yours help) this:

Table:

create table t(a integer, b text);

Function:

CREATE OR REPLACE FUNCTION f()
  RETURNS SETOF record AS
$$
BEGIN

RETURN QUERY EXECUTE 'SELECT * FROM t';

END;
  $$
  LANGUAGE plpgsql VOLATILE

type:

CREATE TYPE y AS (
    a int,
    b text
);

and now is possible?:

select * from f() as y;

y name in my case is a variable an I create it in an other function

役に立ちましたか?

解決

It could work like this:

CREATE OR REPLACE FUNCTION tt_query(orig_name regclass, data_tt timestamp)
  RETURNS SETOF record AS
$func$
BEGIN

EXECUTE 'CREATE OR REPLACE TEMP VIEW tmp as 
select * 
from  '
|| orig_name 
|| ' where trigger_changed >'
|| quote_literal(data_tt)
|| ' ORDER BY trigger_changed DESC';

-- other work on view tmp

-- return the rows of view temp
RETURN QUERY
SELECT * FROM tmp;

END
$func$  LANGUAGE plpgsql;
  • Note the use of the object identifier type regclass to automatically avoid SQL injection.

  • Do not use the outdated syntax var ALIAS for $1 if you don't have to. Declare parameter names instead.

  • I wouldn't use the keyword temp as identifier, even if that is allowed. Using tmp instead.

  • Use RETURN QUERY to return a set of records. This can even be a static call without EXECUTE. However, you are returning anonymous records and Postgres demands a column definition list with every call:

SELECT * FROM tt_query('tbl_name', '2014-02-15 12:00')
AS f(col1 int, col2 text, ...);

This is rather unwieldy.

Better solutions

If you know the return type (even if table names are changing, there list of columns may share the same types), declare it at creation time. Consider this related question:
PostgreSQL: ERROR: 42601: a column definition list is required for functions returning "record"

If the return type varies with the the provided table name, there is still a much better solution. Since you are creating a view with SELECT * FROM tbl, you can utilize the well-known type of the table itself as polymorphic parameter:

CREATE OR REPLACE FUNCTION tt_query(orig_name anyelement, data_tt timestamp)
  RETURNS SETOF anyelement AS
$func$
BEGIN

EXECUTE format('CREATE OR REPLACE TEMP VIEW tmp AS
   SELECT * FROM  %s
   WHERE  trigger_changed > %L
   ORDER  BY trigger_changed DESC'
  ,pg_typeof(orig_name)
  ,data_tt);

-- other work on view tmp

-- return the rows of view tmp
RETURN QUERY
SELECT * FROM tmp;

END
$func$  LANGUAGE plpgsql;

Simplified Call:

SELECT * FROM tt_query(NULL::tbl_name, '2014-02-15 12:00');

Also using format() for safe & simple string concatenation.

More details in this related answer:
Refactor a PL/pgSQL function to return the output of various SELECT queries

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top