Postgres SQL,如何在两个连续 ID 之间复制/插入时自动增加 ID?
Postgres SQL, how to automatically increment ID when duplicate / insert between two sequential ID's?
我有一个 table 以 SERIAL ID 作为主键。
如您所知,序列号会自动递增,我的 table.
需要此功能
ID | info
---------
1 | xxx
2 | xxx
3 | xxx
关于排序问题,我想在 1 和 2 之间插入一行。因此为新行指定一个等于 2 的 ID,并希望其他 ID 自动递增到 3,4。如果我执行这样的查询,我会收到重复键错误。
有没有办法让它成为可能,也许将 SERIAL ID 更改为其他类型?
你所描述的不是大多数人认为的ID,它应该是一个永久的、任意的标识符,自增列只是一种创建唯一值的便捷方式。例如,您不能将不断变化的值用作外键,因此可能需要两列。
但是,您所描述的任务只需一个普通的 Integer 列即可轻松实现,我们称其为 "position",因为这似乎是此行为的更合乎逻辑的标签。
算法简单:
- 通过将所有现有元素向上移动一位来为新值创建 space。
- 插入新元素。
在 SQL 中,看起来像这样,在位置 42 处插入:
UPDATE items SET position=position + 1 WHERE position >= 42;
INSERT INTO items ( position, name ) VALUES ( 42, 'Answer' );
您可以将其包装在服务器上的 SQL 函数中,并将其包装在事务中以防止并发插入相互混淆。
请注意,默认情况下,position
列上的 PRIMARY KEY
或 UNIQUE
约束在更新期间可能会失效,因为对每一行的更改都是单独验证的。要解决这个问题,您可以使用 "deferrable constraint";即使在 "immediate" 模式下,也只会在语句末尾检查,因此更新不会违反它。
CONSTRAINT uq_position UNIQUE (position) DEFERRABLE INITIALLY IMMEDIATE
另请注意,Serial 列不必是唯一的,因此您仍然可以将默认值设置为自动递增。但是,它不会注意到您插入了额外的值,因此您需要在手动插入后重置序列:
SELECT setval(
pg_get_serial_sequence('items', 'position'),
( SELECT max(position) FROM items )
);
这里是live demo putting it all together。 (SQLFiddle 似乎有一个不是 dropping/resetting 序列的错误,使得 id
值看起来很奇怪。)
我有一个 table 以 SERIAL ID 作为主键。 如您所知,序列号会自动递增,我的 table.
需要此功能ID | info
---------
1 | xxx
2 | xxx
3 | xxx
关于排序问题,我想在 1 和 2 之间插入一行。因此为新行指定一个等于 2 的 ID,并希望其他 ID 自动递增到 3,4。如果我执行这样的查询,我会收到重复键错误。
有没有办法让它成为可能,也许将 SERIAL ID 更改为其他类型?
你所描述的不是大多数人认为的ID,它应该是一个永久的、任意的标识符,自增列只是一种创建唯一值的便捷方式。例如,您不能将不断变化的值用作外键,因此可能需要两列。
但是,您所描述的任务只需一个普通的 Integer 列即可轻松实现,我们称其为 "position",因为这似乎是此行为的更合乎逻辑的标签。
算法简单:
- 通过将所有现有元素向上移动一位来为新值创建 space。
- 插入新元素。
在 SQL 中,看起来像这样,在位置 42 处插入:
UPDATE items SET position=position + 1 WHERE position >= 42;
INSERT INTO items ( position, name ) VALUES ( 42, 'Answer' );
您可以将其包装在服务器上的 SQL 函数中,并将其包装在事务中以防止并发插入相互混淆。
请注意,默认情况下,position
列上的 PRIMARY KEY
或 UNIQUE
约束在更新期间可能会失效,因为对每一行的更改都是单独验证的。要解决这个问题,您可以使用 "deferrable constraint";即使在 "immediate" 模式下,也只会在语句末尾检查,因此更新不会违反它。
CONSTRAINT uq_position UNIQUE (position) DEFERRABLE INITIALLY IMMEDIATE
另请注意,Serial 列不必是唯一的,因此您仍然可以将默认值设置为自动递增。但是,它不会注意到您插入了额外的值,因此您需要在手动插入后重置序列:
SELECT setval(
pg_get_serial_sequence('items', 'position'),
( SELECT max(position) FROM items )
);
这里是live demo putting it all together。 (SQLFiddle 似乎有一个不是 dropping/resetting 序列的错误,使得 id
值看起来很奇怪。)