Postgresql
僅更新 UPSERT 中更改的行的語法簡寫
我有一個查詢,當鍵衝突時,只有在其他列之一發生更改時才將其插入 Postgres(以避免不必要的插入和返回的行,而實際上沒有任何更改):
INSERT INTO public.test_upsert (some_id, a, b, note) VALUES ('c', 1, true, 'asdf') ON CONFLICT (some_id) DO UPDATE SET a = excluded.a, b = excluded.b, note = excluded.note WHERE test_upsert.a IS DISTINCT FROM excluded.a OR test_upsert.b IS DISTINCT FROM excluded.b OR test_upsert.note IS DISTINCT FROM excluded.note RETURNING *;
我的問題是:這個有速記嗎?當插入的任何列與現有列不同時,我基本上想插入一條新記錄更新行。單獨寫出每一列會變得非常冗長,儘管它更明確。
SQL 中沒有規定說*“除此之外的所有列”*。
jsonb
(你可以用or做類似的事情hstore
。)相關答案的詳細資訊:再三考慮,你不需要這個。您不妨更新所有列。無論如何,Postgres 都會寫一個新的行版本,沒有任何損失。
INSERT INTO test_upsert AS t (some_id, a, b, note) -- list is optional VALUES ('c', 5, true, 'asdf') ON CONFLICT (some_id) DO UPDATE SET (some_id, a, b, note) = ROW (excluded.*) -- ROW syntax WHERE (t.*) IS DISTINCT FROM (excluded.*) -- again, compare whole row RETURNING *;
您仍然需要為 的目標列表拼出一次
SET
列列表。這是必需的。其餘的可以縮短。無論如何,您甚至可以
INSERT
在針對所有列的同時省略目標列表,但在大多數情況下,將其拼寫出來是一種很好的形式,對未來的變化更加健壯。表別名是可選的附加語法簡寫。請注意,與大多數地方的表別名不同
AS
,目標的表別名需要關鍵字。INSERT
甚至更短,但是:
... WHERE t IS DISTINCT FROM excluded ...
我們也可以將表名(或別名)用於(眾所周知的!)複合類型。唯一的極端情況缺點:如果還有一個同名的列“t”(或“排除”),由於 Postgres 語法規則,它優先。
(t.*) IS DISTINCT FROM (excluded.*)
不會弄錯,是稍微安全一點的形式。相關答案: