我有一个超过一百万行的表。我需要重置序列并使用新值(1、2、3、4 ...等)重新分配ID列。有什么简单的方法吗?
id
s并不是从1开始的。所以排序结果如下:150、151 ...,300、1、2 ...如果我没有重新编号,最终会导致重复的id错误。 ID。此外,order by id
通常比order by好created_at
。这就是对我有用的东西。
我有一个超过一百万行的表。我需要重置序列并使用新值(1、2、3、4 ...等)重新分配ID列。有什么简单的方法吗?
id
s并不是从1开始的。所以排序结果如下:150、151 ...,300、1、2 ...如果我没有重新编号,最终会导致重复的id错误。 ID。此外,order by id
通常比order by好created_at
。这就是对我有用的东西。
Answers:
如果您不想保留ID的顺序,则可以
ALTER SEQUENCE seq RESTART WITH 1;
UPDATE t SET idcolumn=nextval('seq');
我怀疑是否有一种简单的方法可以按您选择的顺序执行此操作,而无需重新创建整个表。
ALTER SEQUENCE seq RESTART WITH 1;
吗?
SELECT setval('seq', 1, FALSE)
应该做同样的事情(这里,第三个参数FALSE做魔术,因为它表明nextval
必须是1而不是2)
在PostgreSQL 8.4或更高版本中,不再需要指定WITH 1
。将使用CREATE SEQUENCE
由记录或最后设置的起始值ALTER SEQUENCE START WITH
(最有可能是1)。
重置顺序:
ALTER SEQUENCE seq RESTART;
然后更新表的ID列:
UPDATE foo SET id = DEFAULT;
资料来源:PostgreSQL文件
两者都提供的解决方案对我不起作用;
> 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_call为true(Postgres版本9.0.4)
对我有用的解决方案是:
> ALTER SEQUENCE seq RESTART WITH 1;
> UPDATE foo SET id = DEFAULT;
只是为了简化和阐明用于重置序列的ALTER SEQUENCE和SELECT setval的正确用法:
ALTER SEQUENCE sequence_name RESTART WITH 1;
相当于
SELECT setval('sequence_name', 1, FALSE);
无论是陈述的,可以使用重置序列,你可以得到由NEXTVAL(“SEQUENCE_NAME”)的下一个值规定在这里也:
nextval('sequence_name')
就我而言,我通过以下方式实现了这一目标:
ALTER SEQUENCE table_tabl_id_seq RESTART WITH 6;
我的表在哪里命名表
受其他答案的启发,我创建了一个SQL函数来进行序列迁移。该函数将主键序列移动到新的连续序列,该序列以现有序列范围之内或之外的任何值(> = 1)开头。
我将在此处解释如何在将具有相同架构但值不同的两个数据库迁移到一个数据库中时使用此功能。
首先,该函数(将打印生成的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
采用以下参数:
arg_table
:表格名称(例如'example'
)arg_column
:主键列名称(例如'id'
)arg_sequence
:序列名称(例如'example_id_seq'
)arg_next_value
:迁移后列的下一个值它执行以下操作:
nextval('example_id_seq')
遵循max(id)
,并且序列从1开始。这也处理的情况arg_next_value > max(id)
。arg_next_value
。键值的顺序被保留,但范围中的孔未被保留。为了演示,我们使用定义如下的序列和表(例如使用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)
即使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();
如果您使用的是pgAdmin3,请展开“序列”,右键单击序列,转到“属性”,然后在“定义”选项卡中将“当前值”更改为所需的任何值。无需查询。