如何在更新时自动增加串行列?

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。如何创建一个在更新时自动递增的序列?

Erw*_*ter 8

这是一个不寻常的请求,因为人们通常不想更改现有的序列号。(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更有意义:UNIQUEfruits.name

CREATE TABLE public.fruits (
  id serial PRIMARY KEY
, name varchar NOT NULL UNIQUE -- !
);
Run Code Online (Sandbox Code Playgroud)