我想交换两个表的名称。表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。
对象的真实身份是其对象 ID,这是一个数字,用于在其他内部数据库事务的外键约束中引用对象(大多数函数体除外)。重命名对象不会改变其身份。您必须删除并重新创建外键约束。
如果您使用
rename table
命令,则会自动重命名链接到该表的所有依赖项对象、外键、引用。例如:
ALTER TABLE public.table1 RENAME TO table2;
使用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;