首页 > 解决方案 > 如果 NEW 等于 OLD 而没有触发器,则 Postgres 跳过更新

问题描述

假设我有一个表,我需要使用新的、更改的和未更改的现有数据的混合来更新(由于遗留原因,我们不能将它们分成 3 个不同的调用)。

最小的示例表是这样的:

(
    id        integer,
    name      text
        constraint name_unique
            unique,
    metadata  jsonb,
    version   integer default 0
);

有 3 件不同的事情需要发生:

  1. name如果不存在则插入新值( INSERT ... ON CONFLICT (name) ...)
  2. 更新和metadata碰撞if已经存在并且<- 这是我不能用语法写下来的那个,因为它只有(?)让我可以访问value as而不是手头的值 in 。version1nameOLD.metadata <> NEW.metadataON CONFLICTNEWEXCLUDEDROW
  3. 跳过更新和版本碰撞如果OLD.metadata = NEW.metadata

我目前最好的猜测是转换jsonb为纯文本,看看两者是否相同,但我不知道是否可以在不必编写 aFUNCTION和 a 的情况下做到这一点TRIGGER

这三件事可以在一个查询中执行吗?

标签: postgresqlpostgresql-9.6

解决方案


EXCLUDED您可以在ON CONFLICT ... DO UPDATE子句中引用新的行版本:

INSERT INTO tab (name, metadata)
VALUES ('obadja', '{"silly": 42}')
ON CONFLICT ON name_unique
DO UPDATE SET metadata = EXCLUDED.metadata,
              version = tab.version + 1
WHERE tab.metadata IS DISTINCT FROM EXCLUDED.metadata;

推荐阅读