简体   繁体   English

如何在plpgsql中使用变量作为表名

[英]How to use variable as table name in plpgsql

I'm new to plpgsql.我是 plpgsql 的新手。 I'm trying to run a simple query in plpgsql using a variable as table name in plpgsql.我正在尝试使用变量作为 plpgsql 中的表名在 plpgsql 中运行一个简单的查询。 But the variable is being interpreted as the table name instead of the value of the variable being interpreted as variable name.但是变量被解释为表名,而不是被解释为变量名的变量值。

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;

Some background information.一些背景资料。 For every table in my database, I have another table starting with "z_".对于我数据库中的每个表,我都有另一个以“z_”开头的表。 Eg for a table called "employee" I have identical table called "z_employee".例如,对于一个名为“employee”的表,我有一个名为“z_employee”的相同表。 z_employee contains the same set of data as employee. z_employee包含与员工相同的数据集。 I use it to restore the employee table at the start of every test.我用它在每次测试开始时恢复员工表。

When I run this function I get the following error:当我运行此函数时,出现以下错误:

ERROR:  relation "z_table" does not exist
LINE 1: SELECT max(id) from z_table

My guess is that I'm not allowed to use the variable z_table in the SQL query.我的猜测是我不允许在 SQL 查询中使用变量z_table At least not the way I'm using it here.至少不是我在这里使用它的方式。 But I don't know how it's supposed to be done.但我不知道它应该如何完成。

Use dynamic SQL with EXECUTE , simplify, and escape identifiers properly:使用带有EXECUTE动态 SQL,正确地简化和转义标识符:

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 names may need to be quoted to defend against syntax errors or even SQL injection!可能需要引用表名以防止语法错误甚至 SQL 注入! I use the convenient format() to concatenate the DELETE statement and escape identifiers properly.我使用方便的format()来连接DELETE语句并正确转义标识符。

  • A separate SELECT would be more expensive.单独的SELECT会更贵。 You can do it all with a single DELETE statement.您可以使用单个DELETE语句完成所有操作。

Related:有关的:

Aside:在旁边:

You might use the (slightly faster) system catalog pg_tables instead:您可以使用(稍微快一点)系统目录pg_tables代替:

      SELECT tablename
      FROM   pg_catalog.pg_tables
      WHERE  schemaname = 'public'
      AND    tablename NOT LIKE 'z_%'

See:看:

table_catalog in information_schema.tables has no equivalent here. information_schema.tables中的table_catalog在这里没有等效项。 Only tables of the current database are visible anyway.无论如何,只有当前数据库的表是可见的。 So the above predicate WHERE table_catalog = 'my_database' produces an empty result set when connected to the wrong database.所以当连接到错误的数据库时,上面的谓词WHERE table_catalog = 'my_database'会产生一个空的结果集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM