【问题标题】:Why are sequences not updated when COPY is performed in PostgreSQL?为什么在 PostgreSQL 中执行 COPY 时序列不更新?
【发布时间】:2012-02-01 06:32:08
【问题描述】:

我在 PostgreSQL 中使用 COPY 语句插入批量记录。我意识到,序列 ID 没有得到更新,当我稍后尝试插入记录时,它会抛出重复的序列 ID。执行COPY后是否应该手动更新序列号以获取记录数?是不是在执行COPY的时候没有解决办法,只增加序列变量,也就是表的主键字段?请就此澄清一下。提前致谢!

例如,如果我插入 200 条记录,COPY 会很好,我的表会显示所有记录。当我稍后手动插入一条记录时,它会显示duplicate sequence ID error。这很好地暗示了它在复制期间没有增加序列 ID,因为在正常插入期间工作正常。不是指示序列 ID 设置最大记录数,而是有任何机制来指导 COPY 命令在其批量复制选项期间增加序列 ID?

【问题讨论】:

    标签: sql postgresql sequence


    【解决方案1】:

    你问:

    是否应该手动更新序列号以获取执行 COPY 后的记录数?

    是的,你应该像documented here

    在 COPY FROM 之后更新序列值:

    | BEGIN;
    | COPY distributors FROM 'input_file';
    | SELECT setval('serial', max(id)) FROM distributors;
    | END;
    

    你写:

    在复制期间它没有增加序列 ID,因为在正常插入期间工作正常

    但事实并非如此! :) 当您执行正常的 INSERT 时,通常您不会为 SEQUENCE 支持的主键指定显式值。如果你这样做了,你会遇到和现在一样的问题:

    postgres=> create table uh_oh (id serial not null primary key, data char(1));
    NOTICE:  CREATE TABLE will create implicit sequence "uh_oh_id_seq" for serial column "uh_oh.id"
    NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "uh_oh_pkey" for table "uh_oh"
    CREATE TABLE
    postgres=> insert into uh_oh (id, data) values (1, 'x');
    INSERT 0 1
    postgres=> insert into uh_oh (data) values ('a');
    ERROR:  duplicate key value violates unique constraint "uh_oh_pkey"
    DETAIL:  Key (id)=(1) already exists.
    

    当然,您的 COPY 命令提供了一个明确的 id 值,就像上面的示例 INSERT。

    【讨论】:

    • 只有在 INSERT 期间“消耗”一个值以填充默认值时,序列才会递增(内部使用 nextval 函数)。如果您为您的 id 提供值,则不会使用该序列,因此它不会移动。
    【解决方案2】:

    我知道这有点老了,但也许有人仍在寻找答案。

    正如其他人所说的 COPY 的工作方式与 INSERT 类似,因此对于插入到具有序列的表中,您根本不提及序列字段,它会为您处理好。对于 COPY,它的工作方式完全相同。但它不是 COPY 要求表中的所有字段都存在于文本文件中吗?正确答案是 NO,它没有,但它是默认行为。

    要复制并保留序列,请执行以下操作:

    COPY $YOURSCHEMA.$YOURTABLE(col1,col2,col3,col4) FROM '$your_input_file' DELIMITER ',' CSV HEADER;
    

    之后无需手动更新架构,它可以按预期工作,并且在我的测试中几乎一样快。

    【讨论】:

    • 只是添加到此,源(输入)文件只需要包含您要复制的列。 Postgres 不是“聪明的”——它不会查看列标题来匹配您在复制命令中命名的列。因此,在上面的@Phobos 示例中,输入文件必须只有 4 列。只是希望能给别人省点麻烦——这个答案对我有帮助。
    【解决方案3】:

    您可以复制到姐妹表,然后 insert into mytable select * from sister - 这会增加序列。

    如果您加载的数据有 id 字段,请不要选择它进行插入:insert into mytable (col1, col2, col3) select col1, col2, col3 from sister

    【讨论】:

      猜你喜欢
      • 2011-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-30
      • 2014-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多