PostgreSQL如何复制一行记录

67

这是我的表web_book的结构:

     Column     |          Type          |                       Modifiers                       
----------------+------------------------+-------------------------------------------------------
 id             | integer                | not null default nextval('web_book_id_seq'::regclass)
 page_count     | integer                | not null
 year_published | integer                | not null
 file           | character varying(100) | not null
 image          | character varying(100) | not null
 display_on_hp  | boolean                | not null
 name           | character varying(128) | not null
 description    | text                   | not null
 name_cs        | character varying(128) | 
 name_en        | character varying(128) | 
 description_cs | text                   | 
 description_en | text                   |
... 我想复制这一行,但尝试以下代码无效:
INSERT INTO web_book SELECT * FROM web_book WHERE id=3;

我理解的是:

ERROR:  duplicate key value violates unique constraint "web_book_pkey"
DETAIL:  Key (id)=(3) already exists
4个回答

110

您需要为新插入的行创建一个新的ID:

INSERT INTO web_book( 
   id, page_count, year_published, file, image, 
   display_on_hp, name, description, name_cs, 
   name_en, description_cs, description_en
)
SELECT nextval('web_book_id_seq'), 
       page_count, 
       year_published, 
       file, 
       image, 
       display_on_hp, 
       name, 
       description, 
       name_cs, 
       name_en, 
       description_cs, 
       description_en 
FROM web_book WHERE id=3;

如ClodoaldoNeto所述,您可以通过简单地省略ID列并让默认定义发挥作用来使事情变得更加容易:

INSERT INTO web_book( 
   page_count, year_published, file, image, 
   display_on_hp, name, description, name_cs, 
   name_en, description_cs, description_en
)
SELECT page_count, 
       year_published, 
       file, 
       image, 
       display_on_hp, 
       name, 
       description, 
       name_cs, 
       name_en, 
       description_cs, 
       description_en 
FROM web_book WHERE id=3;

在这种情况下,您不需要知道序列名称(但可能不太明显发生了什么)。


7
因为id列的默认值是nextval,所以不需要声明它。翻译后的代码如下:INSERT INTO web_book( page_count, ...) SELECT page_count, ... - Clodoaldo Neto
@clime:让默认值生效不仅更简单,而且可以避免后续出现其他错误。如果你在序列后面手动添加下一个“id”,那么序列不会自增。下一行中依赖默认值的数据可能会从已经被手动“INSERT”重复的序列中提取一个数字。不要这样做,或者之后使用setval()将序列同步。 - Erwin Brandstetter
有没有可能更改一个值?比如选择一个不同的名称而不是从选择查询返回的名称? - Sandeep Balagopal

16

只有在指定值的情况下才需要指定id列(而这不是您的情况)。您想使用下一个序列web_book_id_seq的值,因此不要在INSERT查询中指定它。

您的INSERT应该像这样:

INSERT INTO web_book (page_count, year_published, file, image, display_on_hp, name, description, name_cs, name_en, description_cs, description_en)
SELECT page_count, year_published, file, image, display_on_hp, name, description, name_cs, name_en, description_cs, description_en
FROM web_book
WHERE id = 3;

3
有时候当有很多列的时候,你可能想要避免复制粘贴所有的列名。
CREATE TEMP TABLE tmp (like web_book);
INSERT INTO tmp SELECT * FROM web_book WHERE id = 3;
UPDATE tmp SET id = nextval('web_book_id_seq');
INSERT INTO web_book SELECT * from tmp;

我认为这使得nextValinsert语句不是一个单一的原子操作,也就是说可能会出现相同的重复键错误。 - Khaled Mashaly

0

另一种选择。

请注意,在此示例中,prtkey和pubkey是使用bytea类型的二进制字段。uptime是一个非空的timestamptz字段。

INSERT INTO keysvc (id,title,pvtkey,pubkey,status,uptime) VALUES( 2, 'ramnode4',null ,null ,1, CURRENT_TIMESTAMP);

with keys as (SELECT pvtkey, pubkey, uptime FROM keysvc where id = 1)
update keysvc set pvtkey=(select pvtkey from keys), pubkey=(select pvtkey from keys), uptime=(select uptime from keys) where id =40;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接