如何在 Postgres 中一次更新多个表?

Bru*_*oLM 5 postgresql dynamic-sql plpgsql update

我有几个结构完全相同的表,我需要更新所有表中的值。

为此,我尝试构建以下脚本:

DO
$do$
DECLARE
  i pg_tables%rowtype;
BEGIN
FOR i IN SELECT * FROM pg_catalog.pg_tables where schemaname like 'public' and tablename like '%_knex_migrations'
LOOP
    UPDATE i.tablename SET name = replace(name, '.js', '.ts');
END LOOP;
END
$do$;
Run Code Online (Sandbox Code Playgroud)

我可以看到它i.tablename具有正确的值(我插入到 tmp 表中进行检查),但更新失败。

name: error
length: 223
severity: ERROR
code: 42P01
internalPosition: 8
internalQuery: UPDATE i."tablename" SET name = replace(name, '.js', '.ts')
where: PL/pgSQL function inline_code_block line 7 at SQL statement
file: parse_relation.c
line: 965
routine: parserOpenTable
Run Code Online (Sandbox Code Playgroud)

只是声明i.tablename上的插件UPDATE不起作用。

有没有办法让它工作?还是一次更新所有表的更简单方法?

Eva*_*oll 6

你实际上很接近..首先创建一些测试数据..

CREATE TABLE foo_knex_migrations ( name )
  AS VALUES ('test.js'),('test2.js'),('bicycles');
CREATE TABLE bar_knex_migrations AS TABLE foo_knex_migrations;
CREATE TABLE baz_knex_migrations AS TABLE foo_knex_migrations;
Run Code Online (Sandbox Code Playgroud)

接下来,我们将使用EXECUTE...FORMAT(), 和%I

DO
$do$
  DECLARE
    i pg_tables%rowtype;
  BEGIN
  FOR i IN SELECT * FROM pg_catalog.pg_tables where schemaname like 'public' and tablename like '%_knex_migrations'
  LOOP
    EXECUTE FORMAT(
      $$
        UPDATE %I
        SET name = replace(name, '.js', '.ts');
      $$,
      i.tablename
    );
  END LOOP;
  END
$do$;


TABLE baz_knex_migrations ;
   name   
----------
 test.ts
 test2.ts
 bicycles
(3 rows)

test=# TABLE foo_knex_migrations ;
   name   
----------
 test.ts
 test2.ts
 bicycles
(3 rows)
Run Code Online (Sandbox Code Playgroud)

作为旁注,

  1. 通常,您应该使用information_schemawhich 是针对此类简单事物标准化的,而速度无关紧要。
  2. 您可能应该UPDATE通过添加WHERE子句来检查是否需要运行。否则,您将毫无意义地重写表格。
  3. 在 SQL 中,我们不使用这样的命名约定。没有必要这样做。如果knex_migrations有多个表,请考虑CREATE SCHEMA knex_migrations存储它们,而不是根据所有表的命名约定来遍历目录。