12

我正在尝试为单元测试目的设置临时表。到目前为止,我设法创建了一个临时表来复制现有表的结构:

CREATE TEMP TABLE t_mytable (LIKE mytable INCLUDING DEFAULTS);

但这缺少原始表中的数据。CREATE TABLE AS我可以改为使用语句将数据复制到临时表中:

CREATE TEMP TABLE t_mytable AS SELECT * FROM mytable;

但随后的结构t_mytable将不相同,例如列大小和默认值不同。是否有一条语句可以复制所有内容?

第一个查询使用的另一个问题LIKE是键列仍然引用SEQUENCE原始表的,因此在插入时将其递增。有没有一种简单的方法可以用自己的序列创建新表,还是我必须手动设置一个新序列?

4

2 回答 2

30

我正在使用以下代码来做到这一点:

CREATE TABLE t_mytable (LIKE mytable INCLUDING ALL);
ALTER TABLE t_mytable ALTER id DROP DEFAULT;
CREATE SEQUENCE t_mytable_id_seq;
INSERT INTO t_mytable SELECT * FROM mytable;
SELECT setval('t_mytable_id_seq', (SELECT max(id) FROM t_mytable), true);
ALTER TABLE t_mytable ALTER id SET DEFAULT nextval('t_my_table_id_seq');
ALTER SEQUENCE t_mytable_id_seq OWNED BY t_mytable.id;
于 2013-09-04T17:51:47.343 回答
10

Postgres 10 或更高版本

Postgres 10 引入了符合 SQL 标准的IDENTITY列(带有少量扩展)。您的表的 ID 列将类似于:

id    integer PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY

手册中的语法。
使用它而不是传统的serial列可以避免序列问题。IDENTITY列自动使用独占的专用序列,即使使用 . 复制规范也是如此LIKE手册:

复制的列定义的任何标识规范只有在指定时才会被复制INCLUDING IDENTITY。为新表的每个标识列创建一个新序列,与与旧表关联的序列分开。

和:

INCLUDING ALL是 的缩写形式INCLUDING DEFAULTS INCLUDING IDENTITY INCLUDING CONSTRAINTS INCLUDING INDEXES INCLUDING STORAGE INCLUDING COMMENTS

现在解决方案更简单:

CREATE TEMP TABLE t_mytable (LIKE mytable INCLUDING ALL);
INSERT INTO t_mytable TABLE mytable;
SELECT setval(pg_get_serial_sequence('t_mytable', 'id'), max(id)) FROM tbl;

如图所示,您仍然可以使用setval()来设置序列的当前值。一个人SELECT就可以了。pg_get_serial_sequence()] 6获取序列的名称。

db<>在这里摆弄

有关的:


原始(旧)答案

您可以从数据库转储或pgAdmin之类的 GUI (它对数据库对象创建脚本进行逆向工程)获取创建脚本,创建一个相同的副本(serial列具有单独的序列),然后运行:

INSERT INTO new_tbl
SELECT * FROM old_tbl;

如果两个表位于同一架构中,则副本不能 100% 相同。显然,表名必须不同。索引名称也会发生冲突。从同一序列中检索序列号也可能不符合您的最佳利益。所以你必须(至少)调整名字。

将副本放在不同的模式中可以避免所有这些冲突。当您像演示的那样从常规表创建临时表时,情况会自动发生,因为临时表驻留在它们自己的临时模式中。

或者查看Francisco对直接复制DDL代码的答案。

于 2012-09-04T14:07:17.963 回答