Wenn man im Merge-Statement die Aktualisierung im "when matched" Zweig auf Fälle beschränken will, bei denen sich tatsächlich Änderungen der Daten ergeben haben - was nicht nur aus Gründen der Performance eine gute Idee ist, sondern auch dann, wenn man in ETL-Operationen eine Historie von Veränderungen pflegen möchte, dann kann man dazu eine Where-Bedingung verwenden, die die Gleichheit neuer und existierender Werte für alle betroffenen Felder überprüft. Zu diesem Zweck habe ich in der Vergangenheit gelegentlich recht unübersichtliche OR-Verknüpfungen verwendet, bei denen NULL-Werte via COALESCE auf einen in den Daten nicht erscheinenden Wert gesetzt wurden. Eine deutlich elegantere Lösung zum Problem findet man bei
Stew Ashton, der für dieses Mapping die DECODE-Funktion einsetzt. Dazu ein Beispiel:
drop table test_merge_src;
create table test_merge_src
as
select rownum id
, 1 col1
, 2 col2
from dual
connect by level <= 10;
select * from test_merge_src;
ID COL1 COL2
---------- ---------- ----------
1 1 2
2 1 2
3 1 2
4 1 2
5 1 2
6 1 2
7 1 2
8 1 2
9 1 2
10 1 2
drop table test_merge_dest;
create table test_merge_dest
as
select rownum id
, 1 col1
, 2 col2
from dual
connect by level <= 10;
update test_merge_dest
set col2 = null
where id > 5;
select * from test_merge_dest;
ID COL1 COL2
---------- ---------- ----------
1 1 2
2 1 2
3 1 2
4 1 2
5 1 2
6 1
7 1
8 1
9 1
10 1
merge into test_merge_dest dst
using (select * from test_merge_src) src
on (src.id = dst.id)
when matched then update
set dst.col1 = src.col1
, dst.col2 = src.col2
where 1 in ( decode(dst.col1, src.col1, 0, 1)
, decode(dst.col2, src.col2, 0, 1)
);
5 Zeilen zusammengeführt.
Natürlich kann diese Liste einzelner DECODE-Elemente auch recht unhandlich werden, bleibt aber in jedem Fall kompakter als eine Verknüpfung zahlloser OR-Elemente.
Nachtrag 20.01.2015: über Twitter bin ich von einem ehemaligen Kollegen an die Funktion SYS_OP_MAP_NONNULL erinnert worden, die man in diesem Zusammenhang natürlich auch einsetzen kann - und die seit 12c auch offiziell
dokumentiert ist.