2010-10-25 5 views

Répondre

-1

Veuillez vous référer à la question this si vous souhaitez utiliser la commande UPSERT/MERGE dans Oracle. Sinon, résolvez simplement votre problème côté client en commençant par count(1), puis en décidant d'insérer ou de mettre à jour.

+1

Vous ne pouvait pas être moins bonne; Oracle a pris en charge l'instruction MERGE depuis Oracle 9i. –

+1

La x-ref est bonne; cela contredit ce que vous dites, cependant. Pas mon -1, mais je sympathise au moins avec. –

2

La façon dont je toujours le faire (en supposant que les données ne sont jamais à supprimer, n'inséré) est à

  • faire d'abord un insert, si cela échoue avec une violation de contrainte unique, alors vous savez que la ligne est là,
  • Ensuite, faire une Malheureusement, de nombreux cadres update

tels que Hibernate traitent toutes les erreurs de base de données (par exemple violation de contrainte unique) que les conditions irrécupérables, il est donc pas toujours facile. (Dans Hibernate la solution est d'ouvrir une nouvelle session/transaction juste pour exécuter cette commande une insert.)

Vous ne pouvez pas faire juste un select count(*) .. where .. que même si cela renvoie zéro, et donc que vous choisissez de faire une insert, entre le moment où vous faites le select et le insert quelqu'un d'autre pourrait avoir insert ed la ligne et par conséquent votre insert échouera.

+0

Même avec la contrainte d'insertion uniquement, l'utilisation de deux transactions peut entraîner des exceptions d'unicité si plusieurs mises à jour sont en train d'écrire dans la table. –

+0

David Mann, je suis désolé de ne pas avoir compris; précisez s'il vous plaît. –

+0

Salut Adrian, je pense juste à un cas où l'instruction UPDATE n'est valide que si les données n'ont pas changé depuis la tentative INSERT, et il y a plusieurs processus qui effectuent les insertions et les mises à jour. À moins que toutes les insertions et mises à jour de la table ne soient synchronisées, le UPDATE peut parfois réussir et parfois il peut échouer en fonction de l'entrelacement des processus. Cela m'a semblé un tel casse-tête jusqu'à ce que je devais effectuer des mises à jour qui ne sont valides que si l'état des données depuis la dernière lecture est toujours le même. –

51

MERGE n'a pas besoin de "tables multiples", mais nécessite une requête en tant que source. Quelque chose comme cela devrait fonctionner:

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); 

Sinon, vous pouvez le faire en 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; 
+1

+1 Je ne connais pas l'instruction 'MERGE', mais comme pour la gestion de l'exception' DUP_VAL_ON_INDEX', c'est vraiment une bonne solution, sachant que la gestion des exceptions Oracle est régulièrement utilisée pour un tel comportement! =) –

+1

+1; Il convient de noter que la solution alternative est généralement beaucoup moins efficace. – DCookie

2

Vous pouvez utiliser la variable Oracle SQL%ROWCOUNT:

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; 

Il serait plus facile de pour déterminer si votre clé primaire (par exemple, field1) a une valeur, puis effectuez une insertion ou une mise à jour en conséquence. C'est-à-dire, si vous utilisez ces valeurs en tant que paramètres pour une procédure stockée.

+8

Si vous avez plusieurs sessions d'écriture simultanée, vous pourriez rencontrer la situation où la 'update' touche zéro rangs donc vous supposez qu'il n'y a pas de ligne et que vous devez faire un' insert', mais en attendant quelqu'un a fait ' insert' donc votre 'insert' échoue avec une violation de contrainte unique. C'est pourquoi il est important de faire 'insert' (et d'attraper les violations de contraintes uniques) puis' update', et non l'inverse. –

4
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 [,...]); 
0

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; 
+0

Rien de spécial à ce sujet parce que le principe de base de ceci était déjà affiché plus tôt. Juste pour s'amuser :) –

+0

Que signifie "HC"? –

+0

Cela signifie hardcore –

Questions connexes