Let's say I have a table I need to update with a mixture of new, changed and unchanged existing data (for legacy reasons we cannot separate them into 3 different calls).
The minimal example table is this:
(
id integer,
name text
constraint name_unique
unique,
metadata jsonb,
version integer default 0
);
There are 3 different things that need to happen:
- Insert the new values if
nameis not there (INSERT ... ON CONFLICT (name) ...) - Update
metadataand bumpversionwith1ifnameis already there andOLD.metadata <> NEW.metadata<- this is the one I cannot write down with theON CONFLICTsyntax as it only(?) gives me access toNEWvalue asEXCLUDEDbut not the value at hand inROW. - Skip update and version bump if
OLD.metadata = NEW.metadata
My current best guess was casting jsonb to plain text and see if the two was the same, but I could not figure out if it was possible to do it without having to write a FUNCTION and a TRIGGER.
Can these 3 things performed in one query?
CodePudding user response:
You can reference the new row version with EXCLUDED in the ON CONFLICT ... DO UPDATE clause:
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;
CodePudding user response:
I think I have solved this problem.
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);
Let me know if I made any mistakes.
