PostgreSQL 可以在 INSERT 冲突时更新另一行吗?

Can PostgreSQL's update the other row on INSERT conflict?

我有一个 table 记录了给定 a 的最近插入的 b:


CREATE TABLE IF NOT EXISTS demo (
    id       serial primary key,
    a        int not null,
    b        int not null,
    current  boolean not null
);

CREATE UNIQUE INDEX ON demo (a, current) WHERE CURRENT = true;


INSERT INTO demo (a, b, current) VALUES (1, 101, true);

我希望能够插入值,当它们发生冲突时,应该更新新行,并且应该更新 先前 冲突的行。

例如我有

select * from demo;
 id | a |  b  | current
----+---+-----+---------
  1 | 1 | 101 | t

然后我 运行 像这样:

INSERT INTO demo (a, b, current)
       VALUES (1, 102, true)
       ON CONFLICT SET «THE OTHER ONE».current = false;

然后我会看到:

select * from demo;
 id | a |  b  | current
----+---+-----+---------
  1 | 1 | 101 | f        <- changed
  2 | 1 | 102 | t

PostgreSQL 中是否有允许这样做的语法?

正如@Adrian 所提议的那样,您可以使用触发器来完成:

CREATE OR REPLACE FUNCTION before_insert ()
RETURNS trigger LANGUAGE plpgsql AS
$$
BEGIN
  UPDATE demo
     SET current = false
   WHERE a = NEW.a ;
  RETURN NEW ;
END ;
$$ ;

CREATE TRIGGER before_insert BEFORE INSERT ON demo
FOR EACH ROW EXECUTE FUNCTION before_insert () ;

查看dbfiddle

中的测试结果

PS :约束 one_per 将防止前几行具有相同的 a 值和 current = false