如何重置 postgres 中的序列并用新数据填充 id 列?
我有一个包含超过一百万行的表。我需要重置序列并使用新值(1、2、3、4...等...)重新分配 id 列。有什么简单的方法可以做到这一点吗?
I have a table with over million rows. I need to reset sequence and reassign id column with new values (1, 2, 3, 4... etc...). Is any easy way to do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(16)
如果您不想保留 id 的顺序,那么我
怀疑是否有一种简单的方法可以按照您选择的顺序执行此操作,而无需重新创建整个表。
If you don't want to retain the ordering of ids, then you can
I doubt there's an easy way to do that in the order of your choice without recreating the whole table.
对于 PostgreSQL 8.4 或更高版本,不再需要指定
WITH 1
。将使用由CREATE SEQUENCE
记录的起始值或由ALTER SEQUENCE START WITH
最后设置的起始值(很可能为 1)。重置序列:
然后更新表的 ID 列:
来源:PostgreSQL Docs
With PostgreSQL 8.4 or newer there is no need to specify the
WITH 1
anymore. The start value that was recorded byCREATE SEQUENCE
or last set byALTER SEQUENCE START WITH
will be used (most probably this will be 1).Reset the sequence:
Then update the table's ID column:
Source: PostgreSQL Docs
重置顺序:
更新当前记录:
Reset the sequence:
Updating current records:
重置序列以从数字 1 开始的最佳方法是执行以下命令:
因此,例如对于 users 表,它将是:
The best way to reset a sequence to start back with number 1 is to execute the following:
So, for example for the users table it would be:
只是为了简化和澄清 ALTER SEQUENCE 和 SELECT setval 重置序列的正确用法:
相当于
任一语句都可以用于重置序列,您可以通过 nextval('sequence_name') 获取下一个值,如此处< /a> 还有:
Just for simplifying and clarifying the proper usage of ALTER SEQUENCE and SELECT setval for resetting the sequence:
is equivalent to
Either of the statements may be used to reset the sequence and you can get the next value by nextval('sequence_name') as stated here also:
两者提供的解决方案都不适合我;
setval('seq', 1)
以 2 开始编号,ALTER SEQUENCE seq START 1
也以 2 开始编号,因为 seq.is_known 为 true (Postgres版本 9.0.4)对我有用的解决方案是:
Both provided solutions did not work for me;
setval('seq', 1)
starts the numbering with 2, andALTER SEQUENCE seq START 1
starts the numbering with 2 as well, because seq.is_called is true (Postgres version 9.0.4)The solution that worked for me is:
要保留行的顺序:
To retain order of the rows:
在我的例子中,导入错误的 sql 文件后,所有表中的序列都已损坏。
SELECT nextval('table_name_id_seq');
返回的值小于id
列的最大值。因此,我创建了 sql 脚本来恢复每个表的所有序列:
注意:如果您的任何表上都没有
id
列,您可以更新逻辑或根据上面的逻辑。In my case sequences in all tables had been corrupted after importing the wrong sql file.
SELECT nextval('table_name_id_seq');
was returning less than max value of theid
column.So, I created sql script to recover all sequences for each table:
Note: If you don't have the
id
column on any of your tables, you would either update the logic or handle them separately based on the logic above.仅供参考:如果您需要在 ID 范围(例如 256 - 10000000)之间指定新的起始值:
FYI: If you need to specify a new startvalue between a range of IDs (256 - 10000000 for example):
仅重置序列并更新所有行可能会导致重复的 id 错误。在许多情况下,您必须将所有行更新两次。首先使用更高的 id 以避免重复,然后使用您真正想要的 id。
请避免向所有 ID 添加固定金额(如其他评论中建议的那样)。如果行数多于这个固定数量,会发生什么情况?假设序列的下一个值高于现有行的所有 id(您只想填补空白),我会这样做:
Just resetting the sequence and updating all rows may cause duplicate id errors. In many cases you have to update all rows twice. First with higher ids to avoid the duplicates, then with the ids you actually want.
Please avoid to add a fixed amount to all ids (as recommended in other comments). What happens if you have more rows than this fixed amount? Assuming the next value of the sequence is higher than all the ids of the existing rows (you just want to fill the gaps), i would do it like:
就我而言,我通过以下方式实现了这一点:
我的表名为table
In my case, I achieved this with:
Where my table is named table
例如,要使用表“TAB_B”的“FIELD_ID”字段的最大值更新序列“SEQ_A”的值,可以使用以下命令:
该命令选择表“TAB_B”的“FIELD_ID”字段的最大值TAB_B”并将其设置为序列“SEQ_A”的下一个值。
For example, to update the value of sequence "SEQ_A" using the maximum value of the "FIELD_ID" field of table "TAB_B," you can use the following command:
This command selects the maximum value of the "FIELD_ID" field of table "TAB_B" and sets it as the next value of sequence "SEQ_A."
如果您使用的是 pgAdmin3,请展开“序列”,右键单击序列,转到“属性”,然后在“定义”选项卡中将“当前值”更改为您想要的任何值。无需查询。
If you are using pgAdmin3, expand 'Sequences,' right click on a sequence, go to 'Properties,' and in the 'Definition' tab change 'Current value' to whatever value you want. There is no need for a query.
受到此处其他答案的启发,我创建了一个 SQL 函数来执行序列迁移。该函数将主键序列移动到一个新的连续序列,该序列以现有序列范围内部或外部的任何值 (>= 1) 开始。
我在此处解释了如何使用此函数将具有相同架构但不同值的两个数据库迁移到一个数据库中。
首先,该函数(打印生成的 SQL 命令,以便它是
清楚实际发生的情况):
函数
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 > 的情况。最大(id)。
arg_next_value
。键值的顺序被保留,但存在漏洞范围不保留。
您想要迁移另一个表的列并与该表合并。
为了进行演示,我们使用如下定义的序列和表(例如使用 psql):
然后,我们插入一些值(例如从 3 开始):
最后,我们迁移
示例.id
值从 1 开始。结果:
Inspired by the other answers here, I created an SQL function to do a sequence migration. The function moves a primary key sequence to a new contiguous sequence starting with any value (>= 1) either inside or outside the existing sequence range.
I explain here how I used this function in a migration of two databases with the same schema but different values into one database.
First, the function (which prints the generated SQL commands so that it is
clear what is actually happening):
The function
migrate_pkey_sequence
takes the following arguments:arg_table
: table name (e.g.'example'
)arg_column
: primary key column name (e.g.'id'
)arg_sequence
: sequence name (e.g.'example_id_seq'
)arg_next_value
: next value for the column after migrationIt performs the following operations:
nextval('example_id_seq')
followsmax(id)
and that the sequence startswith 1. This also handles the case where
arg_next_value > max(id)
.arg_next_value
. The order of key values are preserved but holes in therange are not preserved.
you want to migrate the columns of another table and merge with this one.
To demonstrate, we use a sequence and table defined as follows (e.g. using
psql
):Then, we insert some values (starting, for example, at 3):
Finally, we migrate the
example.id
values to start with 1.The result:
即使自动增量列不是 PK(在本例中称为 seq - 又名序列),您也可以使用触发器来实现:
DROP TABLE IF EXISTS devops_guide CASCADE;
Even the auto-increment column is not PK ( in this example it is called seq - aka sequence ) you could achieve that with a trigger :
DROP TABLE IF EXISTS devops_guide CASCADE;