如何在 plpgsql 中使用变量作为 table 名称
How to use variable as table name in plpgsql
我是 plpgsql 的新手。我正在尝试 运行 plpgsql 中的一个简单查询,使用变量作为 plpgsql 中的 table 名称。但是变量被解释为 table 名称,而不是变量的值被解释为变量名称。
DECLARE
v_table text;
z_table text;
max_id bigint;
BEGIN
FOR v_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_catalog = 'my_database'
AND table_schema = 'public'
AND table_name not like 'z_%'
LOOP
z_table := 'z_' || v_table;
SELECT max(id) from z_table INTO max_id;
DELETE FROM v_table where id > max_id;
END LOOP;
一些背景信息。对于我数据库中的每个 table,我都有另一个以 "z_" 开头的 table。例如。对于名为 "employee" 的 table 我有相同的 table 名为 "z_employee"。 z_employee
包含与员工相同的数据集。我用它在每次测试开始时恢复员工 table。
当我运行这个函数时,我得到以下错误:
ERROR: relation "z_table" does not exist
LINE 1: SELECT max(id) from z_table
我的猜测是不允许我在 SQL 查询中使用变量 z_table
。至少不是我在这里使用它的方式。但是我不知道应该怎么做。
正确使用dynamic SQL with EXECUTE
、简化和转义标识符:
CREATE OR REPLACE FUNCTION f_test()
RETURNS void AS
$func$
DECLARE
v_table text;
BEGIN
FOR v_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_catalog = 'my_database'
AND table_schema = 'public'
AND table_name NOT LIKE 'z_%'
LOOP
EXECUTE format('DELETE FROM %I v WHERE v.id > (SELECT max(id) FROM %I)'
, v_table, 'z_' || v_table);
END LOOP;
END
$func$ LANGUAGE plpgsql;
Table 名称可能需要被引用以防止语法错误甚至 SQL 注入!我使用方便的 format()
连接 DELETE
语句并正确转义标识符。
- 一个单独的
SELECT
会更贵。您可以使用一个 DELETE
语句完成所有操作。
相关:
- Table name as a PostgreSQL function parameter
旁白:
您可以改用(稍微快一些的)系统目录 pg_tables
:
SELECT tablename
FROM pg_catalog.pg_tables
WHERE schemaname = 'public'
AND tablename NOT LIKE 'z_%'
参见:
- How to check if a table exists in a given schema
table_catalog
in information_schema.tables
在这里没有等价物。无论如何,只有 current 数据库的表是可见的。所以当连接到错误的数据库时,上面的谓词 WHERE table_catalog = 'my_database'
会产生一个空的结果集。
我是 plpgsql 的新手。我正在尝试 运行 plpgsql 中的一个简单查询,使用变量作为 plpgsql 中的 table 名称。但是变量被解释为 table 名称,而不是变量的值被解释为变量名称。
DECLARE
v_table text;
z_table text;
max_id bigint;
BEGIN
FOR v_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_catalog = 'my_database'
AND table_schema = 'public'
AND table_name not like 'z_%'
LOOP
z_table := 'z_' || v_table;
SELECT max(id) from z_table INTO max_id;
DELETE FROM v_table where id > max_id;
END LOOP;
一些背景信息。对于我数据库中的每个 table,我都有另一个以 "z_" 开头的 table。例如。对于名为 "employee" 的 table 我有相同的 table 名为 "z_employee"。 z_employee
包含与员工相同的数据集。我用它在每次测试开始时恢复员工 table。
当我运行这个函数时,我得到以下错误:
ERROR: relation "z_table" does not exist
LINE 1: SELECT max(id) from z_table
我的猜测是不允许我在 SQL 查询中使用变量 z_table
。至少不是我在这里使用它的方式。但是我不知道应该怎么做。
正确使用dynamic SQL with EXECUTE
、简化和转义标识符:
CREATE OR REPLACE FUNCTION f_test()
RETURNS void AS
$func$
DECLARE
v_table text;
BEGIN
FOR v_table IN
SELECT table_name
FROM information_schema.tables
WHERE table_catalog = 'my_database'
AND table_schema = 'public'
AND table_name NOT LIKE 'z_%'
LOOP
EXECUTE format('DELETE FROM %I v WHERE v.id > (SELECT max(id) FROM %I)'
, v_table, 'z_' || v_table);
END LOOP;
END
$func$ LANGUAGE plpgsql;
Table 名称可能需要被引用以防止语法错误甚至 SQL 注入!我使用方便的 format()
连接 DELETE
语句并正确转义标识符。
- 一个单独的
SELECT
会更贵。您可以使用一个DELETE
语句完成所有操作。
相关:
- Table name as a PostgreSQL function parameter
旁白:
您可以改用(稍微快一些的)系统目录 pg_tables
:
SELECT tablename
FROM pg_catalog.pg_tables
WHERE schemaname = 'public'
AND tablename NOT LIKE 'z_%'
参见:
- How to check if a table exists in a given schema
table_catalog
in information_schema.tables
在这里没有等价物。无论如何,只有 current 数据库的表是可见的。所以当连接到错误的数据库时,上面的谓词 WHERE table_catalog = 'my_database'
会产生一个空的结果集。