如果 NEW 等于 OLD 没有触发器,Postgres 将跳过更新
Postgres skip update if NEW equals OLD without triggers
假设我有一个 table 我需要混合使用新的、更改的和未更改的现有数据进行更新(由于遗留原因,我们不能将它们分成 3 个不同的调用)。
最小的例子table是这样的:
(
id integer,
name text
constraint name_unique
unique,
metadata jsonb,
version integer default 0
);
需要发生 3 件不同的事情:
- 如果
name
不存在则插入新值 (INSERT ... ON CONFLICT (name) ...
)
- 如果
name
已经存在并且 OLD.metadata <> NEW.metadata
<- 这是我无法写下来的,则 metadata
更新 metadata
并使用 1
增加 version
ON CONFLICT
语法,因为它仅 (?) 允许我访问 NEW
值作为 EXCLUDED
但不是 ROW
. 中手头的值
- 如果
OLD.metadata = NEW.metadata
跳过更新和版本提升
我目前最好的猜测是将 jsonb
转换为纯文本并查看两者是否相同,但我不知道是否可以在不必编写 [=24= 的情况下做到这一点] 和 TRIGGER
.
这 3 件事可以在一个查询中执行吗?
我想我已经解决了这个问题。
INSERT
INTO example (id, name, metadata, version)
VALUES (DEFAULT, 'Random', '{}', DEFAULT)
on conflict(name) do
update set
metadata = excluded.metadata,
version = example.version + 1
where
example.name = excluded.name and
cast(example.metadata as text) <> cast(excluded.metadata as text);
如果我有任何错误,请告诉我。
您可以在 ON CONFLICT ... DO UPDATE
子句中使用 EXCLUDED
引用新行版本:
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;
假设我有一个 table 我需要混合使用新的、更改的和未更改的现有数据进行更新(由于遗留原因,我们不能将它们分成 3 个不同的调用)。
最小的例子table是这样的:
(
id integer,
name text
constraint name_unique
unique,
metadata jsonb,
version integer default 0
);
需要发生 3 件不同的事情:
- 如果
name
不存在则插入新值 (INSERT ... ON CONFLICT (name) ...
) - 如果
name
已经存在并且OLD.metadata <> NEW.metadata
<- 这是我无法写下来的,则metadata
更新metadata
并使用1
增加version
ON CONFLICT
语法,因为它仅 (?) 允许我访问NEW
值作为EXCLUDED
但不是ROW
. 中手头的值
- 如果
OLD.metadata = NEW.metadata
跳过更新和版本提升
我目前最好的猜测是将 jsonb
转换为纯文本并查看两者是否相同,但我不知道是否可以在不必编写 [=24= 的情况下做到这一点] 和 TRIGGER
.
这 3 件事可以在一个查询中执行吗?
我想我已经解决了这个问题。
INSERT
INTO example (id, name, metadata, version)
VALUES (DEFAULT, 'Random', '{}', DEFAULT)
on conflict(name) do
update set
metadata = excluded.metadata,
version = example.version + 1
where
example.name = excluded.name and
cast(example.metadata as text) <> cast(excluded.metadata as text);
如果我有任何错误,请告诉我。
您可以在 ON CONFLICT ... DO UPDATE
子句中使用 EXCLUDED
引用新行版本:
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;