Basically, you need the pre-UPDATE
values of updated rows to compare. That's kind of hard as RETURNING
only returns post-UPDATE
state. But can be worked around. See:
So this does the basic trick:
WITH input(col1, col2) AS (
SELECT 1, text 'post_up' -- "whole row"
)
, pre_upd AS (
UPDATE tab1 x
SET (col1, col2) = (i.col1, i.col2)
FROM input i
JOIN tab1 y USING (col1)
WHERE x.col1 = y.col1
RETURNING y.*
)
TABLE pre_upd
UNION ALL
TABLE input;
db<>fiddle here
This is assuming that col1
in your example is the PRIMARY KEY
. We need some way to identify rows unambiguously.
Note that this is not safe against race conditions between concurrent writes. You need to do more to be safe. See related answer above.
The explicit cast to text
I added in the CTE above is redundant as text
is the default type for string literals anyway. (Like integer
is the default for simple numeric literals.) For other data types, explicit casting may be necessary. See:
Also be aware that all updates write a new row version, even if nothing changes at all. Typically, you'd want to suppress such costly empty updates with appropriate WHERE
clauses. See:
While "passing whole rows", you'll have to check on all columns that might change, to achieve that.