我经常需要在应用程序中克隆行,所以我会花很长的时间来完成它:
INSERT INTO mytable (a, b, c)
SELECT a,b,c FROM mytable WHERE id=12;
Run Code Online (Sandbox Code Playgroud)
(id 被声明为 a SERIAL PRIMARY KEY
, 12 是要克隆的行)。
问题是,当我添加新字段时,mytable
我必须记住更新克隆函数以也克隆这些新字段。
我想以更易于维护的方式克隆行。就像是 :
INSERT INTO mytable
SELECT *, id:DEFAULT FROM mytable WHERE id=12;
Run Code Online (Sandbox Code Playgroud)
在我编写本文时,我还认为克隆详细信息行会很好:如果我有一个使用引用完整性声明的详细信息/子表,如下所示:
CREATE TABLE mychild (
id serial PRIMARY KEY,
parentid int REFERENCES mytable(id),
a text
);
Run Code Online (Sandbox Code Playgroud)
我可以用一个命令克隆 mytable 和所有子表,而不是:
id
mychild
,设置parentid
为新的id
PostgreSQL(或扩展)中是否有任何内容可以帮助处理这些情况?
安装附加模块后hstore
,有一种非常简单的方法可以替换各个字段的值,而无需了解其他列的任何信息:
INSERT INTO mytable
SELECT (t1).* -- note the parentheses
FROM (
SELECT t #= hstore('id', nextval(pg_get_serial_sequence('mytable', 'id'))::text) AS t1
FROM mytable t
WHERE id = 12
) sub;
Run Code Online (Sandbox Code Playgroud)
所有柱都text
在此过程中来回铸造。
密切相关的答案,带有详细的解释和更多(可能更快一点)的替代方案:
这更棘手。但基于上述,加上使用数据修改CTE,有一个非常优雅的解决方案:
WITH ins_parent AS (
INSERT INTO mytable
SELECT (p).* -- note the parentheses
FROM (
SELECT t #= hstore('id', nextval(pg_get_serial_sequence('mytable', 'id'))::text) AS p
FROM mytable t
WHERE id = 2
) sub
RETURNING id
)
INSERT INTO mychild
SELECT (c).*
FROM (
SELECT t #= hstore('id', nextval(pg_get_serial_sequence('mychild', 'id'))::text)
#= hstore('parentid', (SELECT id::text FROM ins_parent)) AS c
FROM mychild t
WHERE parentid = 2
) sub;
Run Code Online (Sandbox Code Playgroud)
这对子表中的所有副本使用新的 序列值,并将新的序列值分配给该列。parentid
id