如何在 postgres 中自动交换表名称及其引用而不出现任何问题?

问题描述 投票:0回答:3

我想交换两个表的名称。表A <> 表B。还可以原子地避免任何读/写问题。我知道我可以在交易中做到这一点。

我正在使用 -

CREATE TABLE TableB (LIKE TableA INCLUDING ALL);
创建表格。然后我还将 FK 从
A
复制到
B
。然后我也做了一个
INSERT INTO TABLEA....
来复制数据(与此无关)。完成所有这些后,我使用
ALTER TABLE RENAME
重命名表,以在事务中交换名称
TableA
<>
TableB
。所以
TableA
变成
TableA_Old
并且
TableB
变成新的
TableA
(下面的例子)

但是,这不会更新其他表中对此新表的引用,例如

TableC
仍然持有针对
TableA_Old
的 FK。当我之前在新重命名的表
\d+
(之前是
TableA
)上执行
TableB
操作时,我没有看到引用。他们仍然指向
TableA_Old

这是一个例子

我创建表A

CREATE TABLE TableA (
    id serial PRIMARY KEY
);


testdb=> \d TableA
                            Table "public.tablea"
 Column |  Type   | Collation | Nullable |              Default               
--------+---------+-----------+----------+------------------------------------
 id     | integer |           | not null | nextval('tablea_id_seq'::regclass)
Indexes:
    "tablea_pkey" PRIMARY KEY, btree (id)

我参考TableA创建TableC

CREATE TABLE TableC(
    id serial PRIMARY KEY,
    table_a_id INT,
   CONSTRAINT table_a_table_c_fk
      FOREIGN KEY(table_a_id) 
      REFERENCES TableA(id)
);


\d TableC
                              Table "public.tablec"
   Column   |  Type   | Collation | Nullable |              Default               
------------+---------+-----------+----------+------------------------------------
 id         | integer |           | not null | nextval('tablec_id_seq'::regclass)
 table_a_id | integer |           |          | 
Indexes:
    "tablec_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "table_a_table_c_fk" FOREIGN KEY (table_a_id) REFERENCES tablea(id)

你可以看看参考

现在我使用函数创建

TableB
看起来像
TableA

create or replace function create_table_like(source_table text, new_table text)
returns void language plpgsql
as $$
declare
    rec record;
begin
    execute format(
        'create table %s (like %s including all)',
        new_table, source_table);
    for rec in
        select oid, conname
        from pg_constraint
        where contype = 'f' 
        and conrelid = source_table::regclass
    loop
        execute format(
            'alter table %s add constraint %s %s',
            new_table,
            replace(rec.conname, source_table, new_table),
            pg_get_constraintdef(rec.oid));
    end loop;
end $$;

select create_table_like('TableA', 'TableB');

\d TableB

testdb=> select create_table_like('TableA', 'TableB');
 create_table_like 
-------------------
 
(1 row)

testdb=> \d TableB

                            Table "public.tableb"
 Column |  Type   | Collation | Nullable |              Default               
--------+---------+-----------+----------+------------------------------------
 id     | integer |           | not null | nextval('tablea_id_seq'::regclass)
Indexes:
    "tableb_pkey" PRIMARY KEY, btree (id)

现在我重命名它们

BEGIN;
ALTER TABLE TableA RENAME to TableA_OLD;
ALTER TABLE TableB RENAME to TableA;
COMMIT;

现在,当我查看结构时,参考仍然是来自

TableA_OLD
TableC

testdb=> \d TableA
                            Table "public.tablea"
 Column |  Type   | Collation | Nullable |              Default               
--------+---------+-----------+----------+------------------------------------
 id     | integer |           | not null | nextval('tablea_id_seq'::regclass)
Indexes:
    "tableb_pkey" PRIMARY KEY, btree (id)

testdb=> \d TableB



testdb=> \d TableA_old
                          Table "public.tablea_old"
 Column |  Type   | Collation | Nullable |              Default               
--------+---------+-----------+----------+------------------------------------
 id     | integer |           | not null | nextval('tablea_id_seq'::regclass)
Indexes:
    "tablea_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "tablec" CONSTRAINT "table_a_table_c_fk" FOREIGN KEY (table_a_id) REFERENCES tablea_old(id)

并且

TableC
指着旧桌子 -
REFERENCES tablea_old(id)

testdb=> \d TableC
                              Table "public.tablec"
   Column   |  Type   | Collation | Nullable |              Default               
------------+---------+-----------+----------+------------------------------------
 id         | integer |           | not null | nextval('tablec_id_seq'::regclass)
 table_a_id | integer |           |          | 
Indexes:
    "tablec_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "table_a_table_c_fk" FOREIGN KEY (table_a_id) REFERENCES tablea_old(id)

有没有一种安全的方法可以做到这一点,而无需再次删除和重新创建约束?

我知道我还可以更新

relfilenode
中的
pg_class
指针并交换它们。然而,这是有风险的,因为
TableB
可能有一个稍微不同的外观模式。因此,我想知道是否可以更新系统目录中的其他表或使用不需要删除约束的 DDL。

postgresql schema
3个回答
1
投票

对象的真实身份是其对象 ID,这是一个数字,用于在其他内部数据库事务的外键约束中引用对象(大多数函数体除外)。重命名对象不会改变其身份。您必须删除并重新创建外键约束。


0
投票

如果您使用

rename table
命令,则会自动重命名链接到该表的所有依赖项对象、外键、引用。例如:

ALTER TABLE public.table1 RENAME TO table2;

0
投票

使用ALTER TABLE可以交换表的名称,而无需修改表结构本身。当您需要备份与主表切换时,运行类似下面的代码会有所帮助

ALTER TABLE myschema.tablemain RENAME TO old;
ALTER TABLE myschema.tablemain_backup RENAME TO tablemain;
ALTER TABLE myschema.old RENAME TO tablemain_backup;
© www.soinside.com 2019 - 2024. All rights reserved.