when doing an UPSERT statement with postgres, such as
INSERT INTO tab1.summary(
table_name, target_field, check_n)
VALUES ('tab1', 'col1', 10),
('tab2', 'col2', 10)
ON CONFLICT(table_name, target_field, check_n)
DO UPDATE SET check_n = 20;
, returns nothing as data output, however, the message shows INSERT 0 2, which means that two rows are affected without any error.
However, is there any way to retrieve the number of inserted and updates rows separately as data output?
2
Answers
You can use a
returning
clause: demoAnd if you run it again, forcing the conflict:
Of course this method only works if your batch doesn’t contain the default
check_n=20
, in which case it’d assume it was updated, not inserted. This can be worked around (although a bit invasively) by adding a reflector column: demo2You can observe a hidden system column
xmax
:An upsert will show zero
xmax
for inserted and non-zero for updated rows because under the hood, anupdate
is actually a combination ofinsert
anddelete
: it inserts a new tuple and deletes the old one, marking as outdated and ready to be removed byvacuum
: demoYou can compare that to the reflector column: demo2