我正在尝试创建一个函数来从我的数据库中的多个表中获取字段值。我制作了这样的剧本:
CREATE OR REPLACE FUNCTION get_all_changes() RETURNS SETOF RECORD AS
$$
DECLARE
tblname VARCHAR;
tblrow RECORD;
row RECORD;
BEGIN
FOR tblrow IN SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname='public' LOOP /*FOREACH tblname IN ARRAY $1 LOOP*/
RAISE NOTICE 'r: %', tblrow.tablename;
FOR row IN SELECT MAX("lastUpdate") FROM tblrow.tablename LOOP
RETURN NEXT row;
END LOOP;
END LOOP;
END
$$
LANGUAGE 'plpgsql' ;
SELECT get_all_changes();
但它不起作用,每次显示此错误
tblrow.tablename" not defined in line "FOR row IN SELECT MAX("lastUpdate") FROM tblrow.tablename LOOP"
答案 0 :(得分:2)
您的内部FOR
循环必须使用manual中显示的FOR...EXECUTE
语法:
FOR target IN EXECUTE text_expression [ USING expression [, ... ] ] LOOP
statements
END LOOP [ label ];
在你的情况下,沿着这条线:
FOR row IN EXECUTE 'SELECT MAX("lastUpdate") FROM ' || quote_ident(tblrow.tablename) LOOP
RETURN NEXT row;
END LOOP
中解释了这个原因
通常,您需要在PL / pgSQL函数中生成动态命令,即每次执行时都会涉及不同表或不同数据类型的命令。 PL / pgSQL正常尝试缓存命令计划(如第39.10.2节所述)在这种情况下不起作用。为了处理这类问题,提供了EXECUTE语句[...]
答案 1 :(得分:0)
谢谢, 我终于把我的剧本做成了:
CREATE TABLE IF NOT EXISTS __rsdb_changes (tablename text,"lastUpdate" timestamp with time zone, nums bigint);
CREATE OR REPLACE FUNCTION get_all_changes(varchar[]) RETURNS SETOF __rsdb_changes AS /*TABLE (tablename varchar(40),"lastUpdate" timestamp with time zone, nums integer)*/
$$
DECLARE
tblname VARCHAR;
tblrow RECORD;
row RECORD;
BEGIN
FOREACH tblname IN ARRAY $1 LOOP
/*RAISE NOTICE 'r: %', tblrow.tablename;*/
FOR row IN EXECUTE 'SELECT CONCAT('''|| quote_ident(tblname) ||''') AS tablename, MAX("lastUpdate") AS "lastUpdate",COUNT(*) AS nums FROM ' || quote_ident(tblname) LOOP
/*RAISE NOTICE 'row.tablename: %',row.tablename;*/
/*RAISE NOTICE 'row.lastUpdate: %',row."lastUpdate";*/
/*RAISE NOTICE 'row.nums: %',row.nums;*/
RETURN NEXT row;
END LOOP;
END LOOP;
RETURN;
END
$$
LANGUAGE 'plpgsql' ;
嗯,它有效。但似乎我只能创建一个表来定义返回结构,而不仅仅是RETURNS SETOF RECORD。我是对的吗?
再次感谢。
答案 2 :(得分:0)
回答你的新问题(错误标记为答案):
这可以简单得多。你做不需要创建一个表,只需要定义一个记录类型。
如果有的话,您最好使用CREATE TYPE
创建一个类型,但只有在多个地方需要该类型时,这才有效。对于单个功能,您可以使用RETURNS TABLE
代替:
CREATE OR REPLACE FUNCTION get_all_changes(text[])
RETURNS TABLE (tablename text
,"lastUpdate" timestamp with time zone
,nums integer) AS
$func$
DECLARE
tblname text;
BEGIN
FOREACH tblname IN ARRAY $1 LOOP
RETURN QUERY EXECUTE format(
$f$SELECT '%I', MAX("lastUpdate"), COUNT(*)::int FROM %1$I
$f$, tblname)
END LOOP;
END
$func$ LANGUAGE plpgsql;
使用RETURN QUERY EXECUTE
代替嵌套循环。更简单,更快捷。
列别名仅用作文档,这些名称将被丢弃,以支持RETURNS
子句中直接或间接声明的名称。
将format()
与%I
一起使用,将quote_ident()
和%1$I
的串联替换为另一个参考相同的参数。
count()
通常会返回bigint
类型。转换整数,因为您在返回类型中定义了这样的列:count(*)::int
。