Postgres - 冲突 - 如何知道是不是发生了更新而不是插入 [重复]

Posted

技术标签:

【中文标题】Postgres - 冲突 - 如何知道是不是发生了更新而不是插入 [重复]【英文标题】:Postgres - ON CONFLICT - HOW to know if an UPDATE occurred instead of an INSERT [duplicate]Postgres - 冲突 - 如何知道是否发生了更新而不是插入 [重复] 【发布时间】:2016-07-18 17:02:00 【问题描述】:

我有一张桌子

CREATE TABLE foo
(
    f0 int,
    time_stamp timestamp,
    CONSTRAINT foo_pk PRIMARY KEY (f0)
)

我需要大量写入此表,因此性能是关键。有时,我会写一条具有f0 现有值的记录,并将time_stamp 更新为当前时间。为此,我使用ON CONFLICT..DO UPDATE 子句。

问题是我需要知道是INSERT还是UPDATE

我虽然使用第二个is_update 列。插入时,插入false

`ON CONFLICT .. DO UPDATE set is_update=true`

然后使用RETURNING is_update 得到我想要的。问题在于引入了一个与数据本身无关的附加列。

【问题讨论】:

How to find out if an upsert was an update with PostgreSQL 9.5+ UPSERT? @lad2025 之前没找到这个问题,谢谢。但是,建议的解决方案是我所说的我已经尝试过的,但我想避免,因为我的表中的附加列用于我认为此 UPSERT / ON CONFLICT 功能中缺少的某些功能。 PostgreSQL Upsert differentiate inserted and updated rows using system columns XMIN, XMAX and others 对于遇到此问题的任何人,我强烈建议您查看 LukaszSzozda 和 klin 的这些 cmets 中链接的其他两个答案。 Sagi 的评论不正确,无需在表格中添加一列即可使用这些答案。 【参考方案1】:

您可以在 foo 表上创建触发器函数。然后使用 TG_OP 保留字捕获insert 操作,如果键存在则更新,否则插入新行。尚未对大行进行测试:)

1.创建程序:

CREATE OR REPLACE FUNCTION public.f0_update_on_duplicate()
 RETURNS trigger
 LANGUAGE plpgsql
AS $function$
declare _exists boolean;
begin
  if TG_OP = 'INSERT' then
    select exists(select true from foo where f0 = NEW.f0) into _exists;
    raise notice '%', _exists;
    if _exists = TRUE then
      update foo set time_stamp = NEW.time_stamp where f0 = NEW.f0;
      return NULL;
    else
      return NEW;
    end if;
  end if;
end
$function$;

2.将过程附加到 foo 表:

CREATE TRIGGER update_on_duplicate 
BEFORE INSERT ON foo FOR EACH ROW EXECUTE PROCEDURE
f0_update_on_duplicate();

3.测试插入。这应该用新的时间戳更新 f0(假设 f0 = 5 已经存在于 foo 表中):

INSERT INTO foo (f0, time_stamp) VALUES ( 5, now() );

【讨论】:

【参考方案2】:

使用两列作为时间戳是常见的做法。 creation_timestamp 列将在插入时设置一次。而update_timestamp 会将最后一次覆盖更新的时间戳保留到该记录中。

在每次“更新插入”时,您可以检查是否尚未设置 update_timestamp。

INSERT INTO foo (f0, creation_timestamp) VALUES (1, NOW())
ON CONFLICT (f0)
DO UPDATE
SET f0=EXCLUDED.f0, update_timestamp=NOW()
RETURNING update_timestamp IS NULL

【讨论】:

以上是关于Postgres - 冲突 - 如何知道是不是发生了更新而不是插入 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

银行冲突是不是发生在非 GPU 硬件上?

Postgres UPSERT 语法混乱

您如何有效地确定 Postgres 表是不是有行

如何创作不易发生合并冲突的更改?

如何在 9.414 版本中使用 executemany 忽略 postgres 中的重复项?

如何确定是不是因共享冲突而引发 IOException?