Dienstag, Januar 06, 2015

Merge mit Prüfung auf Ungleichheit

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.

Keine Kommentare:

Kommentar veröffentlichen