L'opération UPSERT met à jour ou insère une ligne dans une table, selon que la table a déjà une ligne qui correspond aux données:
if table t has a row exists that has key X:
update t set mystuff... where mykey=X
else
insert into t mystuff...
Étant donné qu'Oracle ne dispose pas d'une instruction UPSERT spécifique, quelle est la meilleure façon de procéder?
L' instruction MERGE fusionne les données entre deux tables. L'utilisation de DUAL nous permet d'utiliser cette commande. Notez que ce n'est pas protégé contre l'accès simultané.
la source
Le double exemple ci-dessus qui est en PL / SQL était génial car je voulais faire quelque chose de similaire, mais je le voulais côté client ... alors voici le SQL que j'ai utilisé pour envoyer une instruction similaire directement à partir de C #
Cependant, d'un point de vue C #, cela est plus lent que de faire la mise à jour et de voir si les lignes affectées étaient égales à 0 et de faire l'insertion si c'était le cas.
la source
MERGE
, et je préfère utiliser beaucoup plus simpleDELETE
alorsINSERT
.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);
Une autre alternative sans vérification d'exception:
la source
la source
Aucune des réponses données jusqu'à présent n'est sûre face aux accès simultanés , comme indiqué dans le commentaire de Tim Sylvester, et soulèvera des exceptions en cas de courses. Pour résoudre ce problème, le combo d'insertion / mise à jour doit être enveloppé dans une sorte d'instruction de boucle, de sorte qu'en cas d'exception, le tout soit réessayé.
À titre d'exemple, voici comment le code de Grommit peut être encapsulé dans une boucle pour le rendre sûr lorsqu'il est exécuté simultanément:
NB En mode transaction
SERIALIZABLE
, que je ne recommande pas btw, vous pourriez rencontrer ORA-08177: impossible de sérialiser l'accès pour cette exception de transaction à la place.la source
Je voudrais une réponse de Grommit, sauf qu'elle nécessite des valeurs de dupe. J'ai trouvé une solution où elle peut apparaître une fois: http://forums.devshed.com/showpost.php?p=1182653&postcount=2
la source
INSERT (B.CILT, B.SAYFA, B.KUTUK, B.MERNIS_NO) VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO);
?Une note concernant les deux solutions qui suggèrent:
1) Insérer, si exception puis mettre à jour,
ou
2) Mettre à jour, si sql% rowcount = 0 alors insérer
La question de savoir s'il faut insérer ou mettre à jour en premier dépend également de l'application. Vous attendez-vous à plus d'inserts ou de mises à jour? Celui qui est le plus susceptible de réussir doit passer en premier.
Si vous choisissez le mauvais, vous obtiendrez un tas de lectures d'index inutiles. Pas une grosse affaire mais quelque chose à considérer.
la source
J'utilise le premier exemple de code depuis des années. Remarquez non trouvé plutôt que de compter.
Le code ci-dessous est le code éventuellement nouveau et amélioré
Dans le premier exemple, la mise à jour effectue une recherche d'index. Il le faut pour mettre à jour la ligne de droite. Oracle ouvre un curseur implicite et nous l'utilisons pour encapsuler un insert correspondant afin que nous sachions que l'insertion ne se produira que lorsque la clé n'existe pas. Mais l'insert est une commande indépendante et doit effectuer une deuxième recherche. Je ne connais pas le fonctionnement interne de la commande de fusion, mais comme la commande est une seule unité, Oracle aurait pu exécuter l'insertion ou la mise à jour correcte avec une seule recherche d'index.
Je pense que la fusion est meilleure lorsque vous avez un traitement à faire, ce qui signifie prendre des données de certaines tables et mettre à jour une table, éventuellement insérer ou supprimer des lignes. Mais pour le cas d'une seule ligne, vous pouvez considérer le premier cas car la syntaxe est plus courante.
la source
Exemple de copier-coller pour insérer une table dans une autre, avec MERGE:
Résultat:
la source
Essaye ça,
la source
Sur http://www.praetoriate.com/oracle_tips_upserts.htm :
"Dans Oracle9i, un UPSERT peut accomplir cette tâche en une seule instruction:"
la source