Wieder was gelernt

SQL MERGE

Tags: SQL PostgreSQL
2024-09-21

The Documentation says a bit ambiguously:

First, the MERGE command performs a join from data_source to the target table producing zero or more candidate change rows. For each candidate change row, the status of MATCHED or NOT MATCHED is set just once

What kind of join?

It’s source LEFT JOIN target.

Consider these two tables:

hjp=> create table target(id int, m text);
CREATE TABLE
Time: 18.459 ms
hjp=> insert into target(id) values(1), (2), (3), (4);
INSERT 0 4
Time: 5.186 ms
hjp=> create table source(id int);
CREATE TABLE
Time: 4.609 ms
hjp=> insert into source(id) values (3), (4), (5), (6);
INSERT 0 4
Time: 5.708 ms

Then:

hjp=> select * from source left join target on source.id = target.id;
╔════╤═════╤═════╗
║ id │ id  │  m  ║
╟────┼─────┼─────╢
║  3 │   3 │ (∅) ║
║  4 │   4 │ (∅) ║
║  5 │ (∅) │ (∅) ║
║  6 │ (∅) │ (∅) ║
╚════╧═════╧═════╝
(4 rows)

So Ids 3 and 4 will match, 5 and 6 will not match and 1 and 2 will not be considered at all:

hjp=>
merge into target
using source on target.id = source.id
when     matched and source.id is not null then update set m = 'm'
when     matched and source.id is     null then update set m = 'nmo'
when not matched                           then insert values (id, 'nmn')
;
MERGE 4
Time: 0.443 ms
hjp=*> select * from target;
╔════╤═════╗
║ id │  m  ║
╟────┼─────╢
║  1 │ (∅) ║
║  2 │ (∅) ║
║  3 │ m   ║
║  4 │ m   ║
║  5 │ nmn ║
║  6 │ nmn ║
╚════╧═════╝
(6 rows)

The rows 1 and 2 are unaffected, the condition matched and source.id is null can never happen. And not matched only allows an insert, no delete, so it’s clear that we are considering only the source, not the target here.