问题
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
回答1:
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 $1if you don't have to. Declare parameter names instead.I wouldn't use the keyword
tempas identifier, even if that is allowed. Usingtmpinstead.Use
RETURN QUERYto return a set of records. This can even be a static call withoutEXECUTE. 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
来源:https://stackoverflow.com/questions/21778343/plpgsql-function-return-rows-from-a-view-created-from-random-table