Given two tables counter and cnt_source defined like this:
create temporary table counter (key bigint, count bigint);
create unique index counter_key_uniq on counter (key);
create temporary table cnt_source (key bigint, count bigint, add boolean);
insert into cnt_source values (1, 2, true);
insert into cnt_source values (1, 3, true);
I am using the MERGE statement to compile the cnt_source into the counter table:
merge into counter
using (
select key, count, add
from cnt_source
) as source on source.key = counter.key
when matched then update set
count = (
case when source.add
then counter.count + source.count
else counter.count - source.count
end
)
when not matched then insert
values (source.key, source.count)
;
But this unexpectedly triggers ERROR: 23505: duplicate key value violates unique constraint:
CREATE TABLE
CREATE INDEX
CREATE TABLE
INSERT 0 1
INSERT 0 1
ERROR: 23505: duplicate key value violates unique constraint "counter_key_uniq"
DETAIL: Key (key)=(1) already exists.
SCHEMA NAME: pg_temp_56
TABLE NAME: counter
CONSTRAINT NAME: counter_key_uniq
LOCATION: _bt_check_unique, nbtinsert.c:673
I would have expected MERGE to take care of this, but I cannot find any reference on how WHEN MATCHED is determined.
What would be the right approach here?
I have tried rewriting it to an INSERT-like statement with ON CONFLICT DO UPDATE SET but I could not get access to the add field there, which I do need in my updating logic:
insert into counter (key, count)
select key, count from cnt_source as source
on conflict (key) do update set
count = (
case when source.add
then counter.count + source.count
else counter.count - source.count
end
)
;
yields
ERROR: 42P01: missing FROM-clause entry for table "source"
LINE 5: case when source.add
^
LOCATION: errorMissingRTE, parse_relation.c:3761
This is a MRE, the reality is even more complicated.