如何用干净的副本安全地替换旧表?

Dmi*_*kin 4 postgresql sequence ddl dependencies

我创建了一个table_cleanedliketable并从tableinto插入了唯一值table_cleaned。现在我想更换tabletable_cleaned使用

DROP TABLE table;
ALTER TABLE table_cleaned rename to table;
Run Code Online (Sandbox Code Playgroud)

但第一条语句给出了cannot drop table cals_status because other objects depend on it.

我绝对不想使用,cascade因为它会删除所有相关行。

我怎样才能安全地用干净的副本替换旧表?

按照 Erwin Brandstetter 的建议,这是错误消息的缺失细节:

DETAIL:  default value for column id of table cals_status_deduplicated depends on sequence cals_status_id_seq
Run Code Online (Sandbox Code Playgroud)

Erw*_*ter 6

默认情况下,错误消息会告诉您更多信息。喜欢:

ERROR: cannot drop table tbl because other objects depend on it
SQL state: 2BP01
Detail: view v_tbl depends on table tbl
Hint: Use DROP ... CASCADE to drop the dependent objects too.
Run Code Online (Sandbox Code Playgroud)

通用解决方案

Detail在脚本中包含该行中提到的对象。

此外,为了安全地做到这一点,将所有这些都包装在一个事务中,并在处理新表之前写锁定旧表,以避免丢失在转换期间完成的工作:

BEGIN;

LOCK TABLE tbl IN SHARE MODE;

-- prepare tbl_cleaned

DROP VIEW v_tbl;  -- or any other depending object
-- more?

DROP TABLE tbl;
ALTER TABLE tbl_cleaned rename to tbl;

CREATE VIEW v_tbl AS SELECT  ... -- actual definition, see below
-- more?

COMMIT;
Run Code Online (Sandbox Code Playgroud)

可能有更多的依赖对象。相同的程序。

在示例中,要获取视图定义:

SELECT 'CREATE VIEW v_foo1 AS '
    || pg_get_viewdef('v_foo1'::regclass) AS view_definition;
Run Code Online (Sandbox Code Playgroud)

看:

并且您可能希望重命名约束和索引以适应重命名的表 - 或者重命名新表保留这些并使用正确的名称创建。(同样,在删除旧表之前一定要得到定义!)

有关的:

如果有很多依赖对象并且表不是太大,一个好的选择可能是准备新表(可能作为临时表以获得更好的性能),然后TRUNCATE是原始INSERT表和准备好的新表。这样,诸如视图、FK 约束、规则、使用表类型的函数等依赖对象就可以保持原状。看:

或者您可以就地更新旧表?这个相关的答案显示了所有三个变体的代码:

具体解决方案

您的特定错误消息:

ERROR: cannot drop table tbl because other objects depend on it
SQL state: 2BP01
Detail: view v_tbl depends on table tbl
Hint: Use DROP ... CASCADE to drop the dependent objects too.
Run Code Online (Sandbox Code Playgroud)

... 表示您正在 (ab-) 使用序列为多个表生成默认值。或者至少它错误的列所有。解决方案取决于您想如何处理这种情况。

或者您创建了新表,复制了完整的结构,包括根据相同序列的默认值。

通常,您需要一个专用序列。所以你应该让列拥有SEQUENCE

ALTER SEQUENCE cals_status_id_seq OWNED BY tbl_cleaned.id;  -- column in new table *before* switching
Run Code Online (Sandbox Code Playgroud)

DROP TABLE如果序列由要删除的表中的列之一拥有,则仅级联到序列。

有关的:

您可能对IDENTITY避免这种serial列复杂化的列感兴趣。看: