如何在Postgres的PL / pgSQL函数中编写动态SELECT INTO
查询?
假设我有一个名为tb_name
的变量,它填充了FOR
的information_schema.tables
循环。现在我有一个名为tc
的变量,它将获取每个表的行数。我想要以下内容:
FOR tb_name in select table_name from information_schema.tables where table_schema='some_schema' and table_name like '%1%'
LOOP
EXECUTE FORMAT('select count(*) into' || tc 'from' || tb_name);
END LOOP
在这种情况下,tb_name
和tc
的数据类型应该是什么?
CREATE OR REPLACE FUNCTION myfunc(_tbl_pattern text, _schema text = 'public')
RETURNS void AS -- or whatever you want to return
$func$
DECLARE
_tb_name information_schema.tables.table_name%TYPE; -- currently varchar
_tc bigint; -- count() returns bigint
BEGIN
FOR _tb_name IN
SELECT table_name
FROM information_schema.tables
WHERE table_schema = _schema
AND table_name ~ _tbl_pattern -- see below!
LOOP
EXECUTE format('SELECT count(*) FROM %I.%I', _schema, _tb_name)
INTO _tc;
-- do something with _tc
END LOOP;
END
$func$ LANGUAGE plpgsql;
_
)添加所有参数和变量,以避免命名与表列的冲突。只是一个有用的约定。_tc
应该是bigint
,因为这是count()
返回的总函数。_tb_name
的数据类型动态地从其父列派生:information_schema.tables.table_name
%TYPE
。请参阅Copying Types in the manual一章。information_schema.tables
中列出的表吗?有道理,但要注意其含义。看到:
How to check if a table exists in a given schemaEXECUTE
将动态查询返回的单个行或值分配给(行)变量的方法。单个列(如示例中的count
)会自动从行类型中分解,因此我们可以直接分配给标量变量tc
- 就像我们将整行分配给记录或行变量一样。有关:
How to get the value of a dynamically generated field name in PL/pgSQLsearch_path
中可能存在其他同名的表,这将导致完全错误(并且非常混乱!)结果而没有模式限定。偷偷摸摸的虫子!或者这个模式根本不在search_path
中,这会使函数立即引发异常。
How does the search_path influence identifier resolution and the "current schema"~
中使用正则表达式运算符table_name ~ _tbl_pattern
而不是table_name LIKE ('%' || _tbl_pattern || '%')
,这更简单。无论如何都要警惕模式参数中的特殊字符!看到:
PostgreSQL Reverse LIKE
Escape function for regular expression or LIKE patterns
Pattern matching with LIKE, SIMILAR TO or regular expressions in PostgreSQL_schema text = 'public'
。为方便起见,您可能想要也可能不想要。看到:
Assigning default value for type解决your comment:传递值,使用USING
子句,如:
EXECUTE format('SELECT count(*) FROM %I.%I
WHERE some_column = $1', _schema, _tb_name,column_name)
USING user_def_variable;
有关:
看起来你想要%I
的FORMAT
占位符,以便它将你的变量视为标识符。此外,INTO
条款应该超出准备好的声明。
FOR tb_name in select table_name from information_schema.tables where table_schema='some_schema' and table_name like '%1%'
LOOP
EXECUTE FORMAT('select count(*) from %I', tb_name) INTO tc;
END LOOP