Benutzer-Werkzeuge

Webseiten-Werkzeuge


prog:sql_merge_upsert_same_table_syntax

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
prog:sql_merge_upsert_same_table_syntax [2016/08/17 13:19] – [Lösung mit dem Merge Commando] gpipperrprog:sql_merge_upsert_same_table_syntax [2016/08/18 20:58] (aktuell) gpipperr
Zeile 1: Zeile 1:
 +=====Upsert - Mit dem Oracle Merge auf der gleichen Tabelle in einem Befehl ein Update/Insert nach Bedarf durchführen=====
 +
 +==== Normale Lösung mit Update ====
 +
 +Erst suchen, ob es den Wert schon gibt (count(*)) und dann falls ja => ein "**update**", falls kein Datensatz gefunden => ein "**insert**" durchführen.
 +
 +Oder viel einfacher das "**update**" versuchen und auf **SQL%ROWCOUNT** abfragen.
 +
 +<code sql>
 +
 +begin
 +  
 +  update admin_props
 +     set property = 'DIF' 
 +   where property = 'EXPORT_TYPE';
 +  
 +   if sql%rowcount = 0 then
 +     dbms_output.put_line('-- Insert the value');
 +     insert into admin_props (id, description, property, value)
 +     values (1
 +   , 'Type of the interface'
 +   , 'EXPORT_TYPE'
 +   , 'DIF'
 +      );
 +   else
 +      dbms_output.put_line('-- values was updated');
 +   end if;
 +   
 +end;
 +</code>
 +
 +Damit benötigen wir aber immer auch etwas PL/SQL um das umzusetzen.
 +
 +
 +----
 +
 +
 +==== Lösung mit dem Merge Commando ====
 +
 +Das **Merge** Kommando prüft mit der **ON** Klausel auf Gleichheit, nur wenn WERT1=WERT2 = TRUE wird der Match Block durchgeführt.
 +
 +Wir wollen nun, falls der Wert noch nicht in der Tabelle existiert, den Wert neu hinzufügen.
 +
 +Falls er aber schon existiert soll der Wert nur aktualisiert werden.
 +
 +Im ersten Schritt prüfen wir also in der **USING** Klausel mit einem Select auf die gleiche Tabelle, ob es den Wert schon gibt.
 +
 +Das funktioniert aber nicht!
 +
 +Ist der Datensatz nicht in der Tabelle enthalten gibt eine einfache Abfrage kein Ergebnis zum Vergleichen aus!
 +
 +Und damit vergleichen wir <fc #800000>NICHTS</fc> mit etwas in der ON Klausel => das klappt nicht!
 +
 +Daher müssen wir mit der Union Anweisung in der SQL Abfrage ein Ergebnis aus dieser Abfrage erzwingen, so das wenigstens eine Zeile zum Vergleich zurück gegeben wird. 
 +
 +Dies Zeile muss dann den gewünschten ID Value enthalten! 
 +
 +
 +Sonst funktioniert der nächste Update nicht, da ja wieder neu eingefügt wird für die "erzeugte" ID aus der Dual Abfrage!
 +
 +Soll ein Merge auf die gleiche Tabelle durchgeführt werden, muss das using select also immer min eine Zeile mit der richtigen ID für das Insert zurückgeben!
 +
 +<code sql>
 + 
 + merge into admin_props p
 + using (select id
 +    from admin_gcm_props
 + where property = 'EXPORT_TYPE'
 +  union
 +  select 1 from dual) t
 +   on (p.id = t.id)
 + when matched
 + then
 +    update set property = 'DIF'
 + when not matched
 + then
 +   insert (id, description, property, value)
 +   values (   t.id
 + , 'Type of the interface'
 + , 'EXPORT_TYPE'
 + , 'DIF'
 +  );
 +  
 +</code>
 +
 +
 +
 +----
 +
 +
 +===Mögliche Fehler ===
 +
 +ORA-30926: unable to get a stable set of rows in the source tables
 +
 +Darauf achten das die using  Klausel select Abfrage keine doppelten Werte liefert!
 +
 +
 +
 +
 +----
 +
 +==== Quellen ====
 +
 +Für zwei unterschiedliche Tabellen siehe [[prog:sql_update_syntax|Oracle SQL - Update und Merge mit Daten in einer Tabelle mit Werten aus einer zweiten Tabelle]]
 +
 +
 +Doku:
 +
 +Update:
 + * https://docs.oracle.com/database/121/SQLRF/statements_10008.htm#SQLRF01708
 +
 +Merge:
 + * https://docs.oracle.com/database/121/SQLRF/statements_9016.htm#SQLRF01606
  
prog/sql_merge_upsert_same_table_syntax.txt · Zuletzt geändert: 2016/08/18 20:58 von gpipperr