如何重置postgres中的序列并用新数据填充id列?

时间:2011-01-13 08:37:35

标签: postgresql sequence

我有一张超过百万行的表。我需要重置序列并用新值重新分配id列(1,2,3,4 ...等...)。有没有简单的方法呢?

13 个答案:

答案 0 :(得分:148)

如果您不想保留ID的顺序,那么您可以

ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval('seq');

我怀疑有一种简单的方法可以按照您的选择顺序完成,而无需重新创建整个表格。

答案 1 :(得分:35)

重置序列:

SELECT setval('sequence_name', 0);

更新当前记录:

UPDATE foo SET id = DEFAULT;

答案 2 :(得分:30)

使用PostgreSQL 8.4或更新版本时,无需再指定WITH 1。将使用CREATE SEQUENCE或最后由ALTER SEQUENCE START WITH设置的起始值(最可能是1)。

重置序列:

ALTER SEQUENCE seq RESTART;

然后更新表的ID列:

UPDATE foo SET id = DEFAULT;

来源:PostgreSQL Docs

答案 3 :(得分:16)

两种提供的解决方案对我都不起作用;

> SELECT setval('seq', 0);
ERROR:  setval: value 0 is out of bounds for sequence "seq" (1..9223372036854775807)

setval('seq', 1)以2开始编号,ALTER SEQUENCE seq START 1也开始编号为2,因为seq.is_called为true(Postgres版本9.0.4)

对我有用的解决方案是:

> ALTER SEQUENCE seq RESTART WITH 1;
> UPDATE foo SET id = DEFAULT;

答案 4 :(得分:11)

只是为了简化和澄清正确使用 ALTER SEQUENCE SELECT setval 来重置序列:

ALTER SEQUENCE sequence_name RESTART WITH 1;

相当于

SELECT setval('sequence_name', 1, FALSE);

任何一个语句都可以用来重置序列,你可以通过nextval('sequence_name')获得下一个值,如here所述:

nextval('sequence_name')

答案 5 :(得分:7)

重置序列以使用数字1重新开始的最佳方法是执行以下操作:

ALTER SEQUENCE <tablename>_<id>_seq RESTART WITH 1

因此,例如对于users表,它将是:

ALTER SEQUENCE users_id_seq RESTART WITH 1

答案 6 :(得分:4)

仅供参考:如果您需要在一系列ID(例如256 - 10000000)之间指定一个新的起始值:

SELECT setval('"Sequence_Name"', 
       (SELECT coalesce(MAX("ID"),255) 
           FROM "Table_Name" 
           WHERE "ID" < 10000000 and "ID" >= 256)+1
       ); 

答案 7 :(得分:3)

保留行的顺序:

UPDATE thetable SET rowid=col_serial FROM 
(SELECT rowid, row_number() OVER ( ORDER BY lngid) AS col_serial FROM thetable ORDER BY lngid) AS t1 
WHERE thetable.rowid=t1.rowid;

答案 8 :(得分:1)

重置序列并更新所有行可能会导致重复的ID错误。在许多情况下,您必须两次更新所有行。首先使用更高的ID来避免重复,然后使用您真正想要的ID。

请避免向所有ID添加固定金额(按照其他评论中的建议)。如果您的行数多于此固定金额,会发生什么?假设序列的下一个值高于现有行的所有id(你只想填补空白),我会这样做:

UPDATE table SET id = DEFAULT;
ALTER SEQUENCE seq RESTART;
UPDATE table SET id = DEFAULT;

答案 9 :(得分:1)

就我而言,我通过以下方式实现了这一目标:

ALTER SEQUENCE table_tabl_id_seq RESTART WITH 6;

我的表名为 table

答案 10 :(得分:0)

受到其他答案的启发,我创建了一个SQL函数来进行序列迁移。该函数将主键序列移动到新的连续序列,从现有序列范围内部或外部的任何值(> = 1)开始。

我解释here我是如何在将具有相同模式但不同值的两个数据库迁移到一个数据库中时使用此函数的。

首先,该函数(打印生成的SQL命令,使其成为 明确实际发生的事情):

CREATE OR REPLACE FUNCTION migrate_pkey_sequence
  ( arg_table      text
  , arg_column     text
  , arg_sequence   text
  , arg_next_value bigint  -- Must be >= 1
  )
RETURNS int AS $$
DECLARE
  result int;
  curr_value bigint = arg_next_value - 1;
  update_column1 text := format
    ( 'UPDATE %I SET %I = nextval(%L) + %s'
    , arg_table
    , arg_column
    , arg_sequence
    , curr_value
    );
  alter_sequence text := format
    ( 'ALTER SEQUENCE %I RESTART WITH %s'
    , arg_sequence
    , arg_next_value
    );
  update_column2 text := format
    ( 'UPDATE %I SET %I = DEFAULT'
    , arg_table
    , arg_column
    );
  select_max_column text := format
    ( 'SELECT coalesce(max(%I), %s) + 1 AS nextval FROM %I'
    , arg_column
    , curr_value
    , arg_table
    );
BEGIN
  -- Print the SQL command before executing it.
  RAISE INFO '%', update_column1;
  EXECUTE update_column1;
  RAISE INFO '%', alter_sequence;
  EXECUTE alter_sequence;
  RAISE INFO '%', update_column2;
  EXECUTE update_column2;
  EXECUTE select_max_column INTO result;
  RETURN result;
END $$ LANGUAGE plpgsql;

函数migrate_pkey_sequence采用以下参数:

  1. arg_table:表格名称(例如'example'
  2. arg_column:主键列名称(例如'id'
  3. arg_sequence:序列名称(例如'example_id_seq'
  4. arg_next_value:迁移后列的下一个值
  5. 执行以下操作:

    1. 将主键值移动到空闲范围。我认为 nextval('example_id_seq')跟随max(id),序列开始 这也处理了arg_next_value > max(id)
    2. 的情况
    3. 将主键值移至以#开头的连续范围 arg_next_value。键值的顺序被保留,但是中的孔 范围不保留。
    4. 打印序列中的下一个值。如果,这很有用 您希望迁移另一个表的列并与此表合并。
    5. 为了演示,我们使用如下定义的序列和表(例如使用psql):

      # CREATE SEQUENCE example_id_seq
        START WITH 1
        INCREMENT BY 1
        NO MINVALUE
        NO MAXVALUE
        CACHE 1;
      
      # CREATE TABLE example
        ( id bigint NOT NULL DEFAULT nextval('example_id_seq'::regclass)
        );
      

      然后,我们插入一些值(例如,从3开始):

      # ALTER SEQUENCE example_id_seq RESTART WITH 3;
      # INSERT INTO example VALUES (DEFAULT), (DEFAULT), (DEFAULT);
      -- id: 3, 4, 5
      

      最后,我们将example.id值迁移为1开始。

      # SELECT migrate_pkey_sequence('example', 'id', 'example_id_seq', 1);
      INFO:  00000: UPDATE example SET id = nextval('example_id_seq') + 0
      INFO:  00000: ALTER SEQUENCE example_id_seq RESTART WITH 1
      INFO:  00000: UPDATE example SET id = DEFAULT
       migrate_pkey_sequence
      -----------------------
                           4
      (1 row)
      

      结果:

      # SELECT * FROM example;
       id
      ----
        1
        2
        3
      (3 rows)
      

答案 11 :(得分:0)

即使auto-increment列不是PK(在此示例中也称为seq-aka sequence),您也可以通过触发器来实现:

如果存在devops_guide CASCADE,则删除表;

SELECT 'create the "devops_guide" table'
;
   CREATE TABLE devops_guide (
      guid           UUID NOT NULL DEFAULT gen_random_uuid()
    , level          integer NULL
    , seq            integer NOT NULL DEFAULT 1
    , name           varchar (200) NOT NULL DEFAULT 'name ...'
    , description    text NULL
    , CONSTRAINT pk_devops_guide_guid PRIMARY KEY (guid)
    ) WITH (
      OIDS=FALSE
    );

-- START trg_devops_guide_set_all_seq
CREATE OR REPLACE FUNCTION fnc_devops_guide_set_all_seq()
    RETURNS TRIGGER
    AS $$
       BEGIN
         UPDATE devops_guide SET seq=col_serial FROM
         (SELECT guid, row_number() OVER ( ORDER BY seq) AS col_serial FROM devops_guide ORDER BY seq) AS tmp_devops_guide
         WHERE devops_guide.guid=tmp_devops_guide.guid;

         RETURN NEW;
       END;
    $$ LANGUAGE plpgsql;

 CREATE TRIGGER trg_devops_guide_set_all_seq
  AFTER UPDATE OR DELETE ON devops_guide
  FOR EACH ROW
  WHEN (pg_trigger_depth() < 1)
  EXECUTE PROCEDURE fnc_devops_guide_set_all_seq();

答案 12 :(得分:-1)

如果您正在使用pgAdmin3,请展开“序列”,右键单击序列,转到“属性”,然后在“定义”选项卡中将“当前值”更改为您想要的任何值。无需查询。