oracle sql: update if exists else insert [duplicate] (Programare, Sql, Oracle)

Aks a intrebat.

Posibil duplicat:
Oracle: cum să UPSERT (actualizare sau inserare într-un tabel?)

Bună ziua,

Am o tabelă în care o înregistrare trebuie modificată dacă există deja, altfel trebuie inserată o nouă înregistrare.Oracle sql nu acceptă IF EXISTS, , altfel aș fi făcut un if - update - else - insert interogare. M-am uitat la MERGE dar nu funcționează decât pentru mai multe tabele. Ce trebuie să fac?

6 răspunsuri
Tony Andrews

MERGE nu are nevoie de „mai multe tabele”, dar are nevoie de o interogare ca sursă. Ceva de genul acesta ar trebui să funcționeze:

MERGE INTO mytable d
USING (SELECT 1 id, 'x' name from dual) s
ON (d.id = s.id)
WHEN MATCHED THEN UPDATE SET d.name = s.name
WHEN NOT MATCHED THEN INSERT (id, name) VALUES (s.id, s.name);

Alternativ, puteți face acest lucru în PL/SQL:

BEGIN
  INSERT INTO mytable (id, name) VALUES (1, 'x');
EXCEPTION
  WHEN DUP_VAL_ON_INDEX THEN
    UPDATE mytable
    SET    name = 'x'
    WHERE id = 1;
END;

Comentarii

  • +1 Nu știu despre MERGE dar în ceea ce privește excepția DUP_VAL_ON_INDEX aceasta este cu siguranță o soluție bună, știind că gestionarea excepțiilor Oracle este folosită în mod regulat pentru un astfel de comportament! =) –  > Por Will Marcouiller.
  • +1; trebuie remarcat faptul că soluția alternativă este, în general, mult mai puțin eficientă. –  > Por DCookie.
  • Cum se procedează atunci când ID-ul este necunoscut? De exemplu, căutați un rând după nume și doriți să schimbați numele de familie… –  > Por Dumbo.
  • @Dumbo Ar trebui să aveți o constrângere de unicitate pe coloană, nu? –  > Por Yassin Hajaj.
  • Pentru oricine vine la acest fir de discuție în viitor, rețineți că, dacă doriți să vedeți efectiv rezultatele în baza de date OracleSQL după ce ați rulat MERGE INTO statement, asigurați-vă că confirmați tranzacția prin rularea COMMIT; –  > Por Vincent.
Adam Musch
merge into MY_TABLE tgt
using (select [expressions]
         from dual ) src
   on (src.key_condition = tgt.key_condition)
when matched then 
     update tgt
        set tgt.column1 = src.column1 [,...]
when not matched then 
     insert into tgt
        ([list of columns])
     values
        (src.column1 [,...]);

SirGalahad

Ați putea utiliza SQL%ROWCOUNT Oracle:

UPDATE table1
  SET field2 = value2, 
      field3 = value3 
WHERE field1 = value1; 

IF (SQL%ROWCOUNT = 0) THEN 

  INSERT INTO table (field1, field2, field3)
  VALUES (value1, value2, value3);

END IF; 

Ar fi mai ușor să determinați dacă cheia primară (de ex. field1) are o valoare și apoi să efectuați o inserție sau o actualizare în consecință. Aceasta este, dacă utilizați valorile respective ca parametri pentru o procedură stocată.

Comentarii

  • Dacă aveți mai multe sesiuni care scriu simultan, s-ar putea să vă confruntați cu situația în care update atinge zero rânduri, astfel încât să presupuneți că nu există nici un rând și trebuie să efectuați un insert, , dar între timp cineva a făcut un insert astfel încât insert eșuează cu o încălcare a unei constrângeri unice. De aceea, este important să faceți insert (și pentru a detecta încălcări ale constrângerilor unice), apoi update, , nu invers. –  > Por Adrian Smith.
  • Cea mai proastă logică pe care am văzut-o vreodată –  > Por Vimal Bhaskar.
Adrian Smith

Modul în care o fac întotdeauna (presupunând că datele nu vor fi niciodată șterse, ci doar inserate) este următorul

  • În primul rând, efectuați un insert, Dacă nu reușește cu o încălcare a constrângerii unice, atunci știți că rândul este acolo,
  • Apoi faceți un update

Din păcate, multe cadre, cum ar fi Hibernate, tratează toate erorile bazei de date (de exemplu, încălcarea constrângerii unice) ca fiind condiții irecuperabile, astfel încât nu este întotdeauna ușor (în Hibernate, soluția este să deschideți o nouă sesiune/tranzacție doar pentru a o executa pe aceasta). insert comandă).

Nu puteți face doar o comandă select count(*) .. where .. deoarece chiar dacă aceasta returnează zero și, prin urmare, alegeți să faceți un insert, , între momentul în care efectuați comanda select și insert altcineva ar putea avea insertși, prin urmare, să fi putut insert va eșua.

Comentarii

  • Chiar și cu constrângerea de inserare numai, utilizarea a două tranzacții ar putea duce la excepții de unicitate dacă există mai multe actualizări care scriu în tabel. –  > Por David Mann.
  • David Mann, îmi pare rău că nu am înțeles; vă rog să clarificați. –  > Por Adrian Smith.
  • Bună, Adrian, mă gândesc la un caz în care instrucțiunea UPDATE este valabilă numai dacă datele nu s-au modificat de la încercarea de INSERTARE și există mai multe procese care efectuează inserări și actualizări. Cu excepția cazului în care toate inserțiile și actualizările în tabel sunt sincronizate, uneori UPDATE-ul poate reuși, iar alteori poate eșua, în funcție de modul în care procesele se intercalează. Mie mi s-a părut un astfel de caz de colț până când mi s-a cerut să efectuez UPDATE-uri care sunt valabile numai dacă starea datelor de la ultima citire este încă aceeași. –  > Por David Mann.
Jokke Heikkilä

HC-way 🙂

DECLARE
  rt_mytable mytable%ROWTYPE;
  CURSOR update_mytable_cursor(p_rt_mytable IN mytable%ROWTYPE) IS
  SELECT *
  FROM   mytable
  WHERE  ID = p_rt_mytable.ID
  FOR UPDATE;
BEGIN
  rt_mytable.ID   := 1;
  rt_mytable.NAME := 'x';
  INSERT INTO mytable VALUES (rt_mytable);
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN
  <<update_mytable>>
  FOR i IN update_mytable_cursor(rt_mytable) LOOP
    UPDATE mytable SET    
      NAME = p_rt_mytable.NAME
    WHERE CURRENT OF update_mytable_cursor;
  END LOOP update_mytable;
END;

Comentarii

  • Nimic special în acest sens, deoarece principiul de bază a fost deja postat mai devreme. Doar pentru distracție 🙂 –  > Por Jokke Heikkilä.
  • Ce înseamnă „HC”? –  > Por Nicolas Barbulesco.
  • De asemenea, aș adăuga IN OUT NOCOPY la parametrul cursor… Dar a fost acum 3 ani când am postat asta 🙂 –  > Por Jokke Heikkilä.
  • HC înseamnă Hard Core –  > Por javafan.
Pablo Santa Cruz

Vă rugăm să consultați această întrebare dacă doriți să utilizați comanda UPSERT / MERGE în Oracle. În caz contrar, rezolvați problema dvs. pe partea de client, făcând un count(1) mai întâi și apoi să decideți dacă să inserați sau să actualizați.

Comentarii

  • Nu ai putea fi mai puțin corect; Oracle a susținut instrucțiunea MERGE încă de la Oracle 9i. –  > Por Adam Musch.
  • Referința x este bună; totuși, contrazice ceea ce spui. Nu este -1 al meu, dar cel puțin îl simpatizez. –  > Por Jonathan Leffler.

Tags:,