La operación UPSERT actualiza o inserta una fila en una tabla, dependiendo de si la tabla ya tiene una fila que coincida con los datos:
if table t has a row exists that has key X:
update t set mystuff... where mykey=X
else
insert into t mystuff...
Dado que Oracle no tiene una declaración UPSERT específica, ¿cuál es la mejor manera de hacer esto?
La instrucción MERGE combina datos entre dos tablas. Usar DUAL nos permite usar este comando. Tenga en cuenta que esto no está protegido contra el acceso concurrente.
fuente
El ejemplo doble anterior que está en PL / SQL fue genial porque quería hacer algo similar, pero lo quería del lado del cliente ... así que aquí está el SQL que utilicé para enviar una declaración similar directamente desde algún C #
Sin embargo, desde una perspectiva de C #, esto proporciona ser más lento que hacer la actualización y ver si las filas afectadas fueron 0 y hacer la inserción si lo fue.
fuente
MERGE
, y prefiero usar mucho más simpleDELETE
entoncesINSERT
.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);
Otra alternativa sin la verificación de excepción:
fuente
fuente
Ninguna de las respuestas dadas hasta ahora es segura frente a los accesos concurrentes , como se señaló en el comentario de Tim Sylvester, y generará excepciones en caso de carreras. Para solucionarlo, el combo de inserción / actualización debe estar envuelto en algún tipo de declaración de bucle, de modo que en caso de una excepción se vuelva a intentar todo.
Como ejemplo, así es como el código de Grommit se puede envolver en un bucle para que sea seguro cuando se ejecuta simultáneamente:
Nota: en el modo de transacción
SERIALIZABLE
, que no recomiendo por cierto, es posible que se encuentre con ORA-08177: en su lugar, no puede serializar el acceso para las excepciones de esta transacción .fuente
Me gustaría la respuesta de Grommit, excepto que requiere valores de duplicación. Encontré una solución donde puede aparecer una vez: http://forums.devshed.com/showpost.php?p=1182653&postcount=2
fuente
INSERT (B.CILT, B.SAYFA, B.KUTUK, B.MERNIS_NO) VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO);
?Una nota sobre las dos soluciones que sugieren:
1) Insertar, si es una excepción, luego actualizar,
o
2) Actualización, si sql% rowcount = 0 luego inserte
La cuestión de si insertar o actualizar primero también depende de la aplicación. ¿Esperas más inserciones o más actualizaciones? El que tiene más probabilidades de tener éxito debe ir primero.
Si elige el incorrecto, obtendrá un montón de lecturas de índice innecesarias. No es un gran problema, pero sigue siendo algo a tener en cuenta.
fuente
He estado usando el primer ejemplo de código durante años. Aviso no encontrado en lugar de contar.
El siguiente código es el código posiblemente nuevo y mejorado
En el primer ejemplo, la actualización realiza una búsqueda de índice. Tiene que hacerlo para actualizar la fila derecha. Oracle abre un cursor implícito y lo usamos para ajustar una inserción correspondiente para que sepamos que la inserción solo ocurrirá cuando la clave no exista. Pero la inserción es un comando independiente y tiene que hacer una segunda búsqueda. No conozco el funcionamiento interno del comando merge, pero dado que el comando es una sola unidad, Oracle podría haber ejecutado la inserción o actualización correcta con una sola búsqueda de índice.
Creo que fusionar es mejor cuando hay que procesar algo, lo que significa tomar datos de algunas tablas y actualizar una tabla, posiblemente insertando o eliminando filas. Pero para el caso de una sola fila, puede considerar el primer caso ya que la sintaxis es más común.
fuente
Ejemplo de copiar y pegar para insertar una tabla en otra, con MERGE:
Resultado:
fuente
Prueba esto,
fuente
De http://www.praetoriate.com/oracle_tips_upserts.htm :
"En Oracle9i, un UPSERT puede realizar esta tarea en una sola declaración:"
fuente