use*_*636 3 postgresql database-design sequence
在 Postgres 10 中创建序列时,如何在更新时自动递增?(不仅仅是为下一个插入的行分配下一个更高的数字。)
例如,假设我创建了在此页面上找到的下表和序列:
CREATE TABLE fruits(
id SERIAL PRIMARY KEY,
name VARCHAR NOT NULL
);
INSERT INTO fruits(name) VALUES('Orange');
INSERT INTO fruits(id,name) VALUES(DEFAULT,'Apple');
SELECT * FROM fruits;
id | name
----+--------
1 | Apple
2 | Orange
(2 rows)
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它在插入时正确地自动将“id”列加一。但是,如果我进行如下更新:
update fruits
set name = 'Orange2'
where name = 'Orange';
SELECT * FROM fruits;
id | name
----+--------
1 | Apple
How do I get this to auto-increment to 3? --> 2 | Orange2
(2 rows)
Run Code Online (Sandbox Code Playgroud)
如上所示,id=2 的行尚未更新为 id=3。如何创建一个在更新时自动递增的序列?
这是一个不寻常的请求,因为人们通常不想更改现有的序列号。(PK,不能少!)
但是要回答这个问题:使用触发器。
触发函数和触发器示例:
CREATE FUNCTION trg_next_id_on_update()
RETURNS trigger
LANGUAGE plpgsql AS
$func$
BEGIN
NEW.id := nextval(pg_get_serial_sequence('public.fruits', 'id'));
RETURN NEW;
END
$func$;
CREATE TRIGGER next_id_on_update
BEFORE UPDATE ON fruits
FOR EACH ROW
WHEN (NEW.name <> OLD.name)
EXECUTE FUNCTION trg_next_id_on_update();
Run Code Online (Sandbox Code Playgroud)
db<>fiddle这里(对于 Postgres 10)
当然,这会覆盖id
同一 .txt 文件中对该列所做的任何更改UPDATE
。
而且它并不完全是“自动增量”。它从附加的 中分配下一个空闲号码SEQUENCE
。假设这就是你的意思。
请注意WHEN
条件:仅当实际发生变化时才会触发触发器name
。(不想为其他更新更改 ID,对吗?)相关:
您可以通过使用触发表的名称(安全地!)使触发器函数适用于任何给定的表(带有命名serial
) :id
...
NEW.id := nextval(pg_get_serial_sequence(quote_ident(TG_TABLE_SCHEMA)
|| '.' || quote_ident(TG_TABLE_NAME), 'id'));
...
Run Code Online (Sandbox Code Playgroud)
阅读有关触发功能的手册。
有关的:
或者通过硬编码名称来使其不那么通用并且更快一点SEQUENCE
:
...
NEW.id := nextval('public.fruits_id_seq');
...
Run Code Online (Sandbox Code Playgroud)
您可以决定什么是安全且适合您的环境的。
但是您的示例在以下限制下UPDATE
更有意义:UNIQUE
fruits.name
CREATE TABLE public.fruits (
id serial PRIMARY KEY
, name varchar NOT NULL UNIQUE -- !
);
Run Code Online (Sandbox Code Playgroud)