2008-12-01 32 views
30

Desde mi código (Java) Deseo asegurarme de que exista una fila en la base de datos (DB2) después de que se ejecute mi código.¿Tiene DB2 una instrucción "insertar o actualizar"?

Mi código ahora hace un select y si no se devuelve ningún resultado, hace un insert. Realmente no me gusta este código ya que me expone a problemas de concurrencia cuando se ejecuta en un entorno de subprocesos múltiples.

Lo que me gustaría hacer es poner esta lógica en DB2 en lugar de en mi código de Java. ¿Tiene DB2 una declaración insert-or-update? ¿O algo así que pueda usar?

Por ejemplo:

insertupdate into mytable values ('myid') 

Otra forma de hacerlo sería probablemente de hacer siempre el inserto y captura "de SQL de código -803 clave primaria ya existe", pero me gustaría evitar que, si es posible .

+0

¿No sería mejor tener una transacción por hilo? DBMS es bueno con múltiples hilos, es por eso que las transacciones fueron inventadas. Ellos resolverían el problema de concurrencia. – bortzmeyer

+0

Eso no resolverá el problema de concurrencia porque las transacciones solo funcionan bloqueando en una fila ya existente.Si la fila no existe, la transacción no puede bloquearlo y este tipo de operación aún está abierto para problemas de concurrencia – Richard

Respuesta

38

Sí, DB2 tiene la instrucción MERGE, que hará un UPSERT (actualización o inserción).

MERGE INTO target_table USING source_table ON match-condition 
{WHEN [NOT] MATCHED 
      THEN [UPDATE SET ...|DELETE|INSERT VALUES ....|SIGNAL ...]} 
[ELSE IGNORE] 

Ver:

http://publib.boulder.ibm.com/infocenter/db2luw/v9/index.jsp?topic=/com.ibm.db2.udb.admin.doc/doc/r0010873.htm

+2

Ejemplo que sería útil: __mergir en mytable usando (values ​​('col1', 'col2')) como tmp (código, nombre) en mytable.code = tmp.code cuando coinciden luego actualizar set name = col2 '__ – agad

7

Esta respuesta es responder con suerte plenamente la MrSimpleMind consulta tenía en use-update-and-insert-in-same-query y para proporcionar un sencillo ejemplo de trabajo de la declaración de DB2 fusionarse con un escenario de inserción y actualización de una vez (se actualiza el registro con ID 2 y se inserta la ID de registro 3).

CREATE TABLE STAGE.TEST_TAB ( ID INTEGER, DATE DATE, STATUS VARCHAR(10) ); 
COMMIT; 

INSERT INTO TEST_TAB VALUES (1, '2013-04-14', NULL), (2, '2013-04-15', NULL); COMMIT; 

MERGE INTO TEST_TAB T USING (
    SELECT 
    3 NEW_ID, 
    CURRENT_DATE NEW_DATE, 
    'NEW' NEW_STATUS 
    FROM 
    SYSIBM.DUAL 
UNION ALL 
    SELECT 
    2 NEW_ID, 
    NULL NEW_DATE, 
    'OLD' NEW_STATUS 
    FROM 
    SYSIBM.DUAL 
) AS S 
    ON 
    S.NEW_ID = T.ID 
    WHEN MATCHED THEN 
    UPDATE SET 
     (T.STATUS) = (S.NEW_STATUS) 
    WHEN NOT MATCHED THEN 
    INSERT 
    (T.ID, T.DATE, T.STATUS) VALUES (S.NEW_ID, S.NEW_DATE, S.NEW_STATUS); 
COMMIT; 
+1

Funcionó para mí. gracias – Li3ro

+0

Me gustaría señalar que algunas bases de datos ibm usan 'SYSIBM.SYSDUMMY1' como tabla ficticia en lugar de' SYSIBM.DUAL' – tgdn

2

Otra forma es ejecutar estas 2 consultas. Es más sencillo de crear una instrucción MERGE:

update TABLE_NAME set FIELD_NAME=xxxxx where MyID=XXX; 

INSERT INTO TABLE_NAME values (MyField1,MyField2) 
WHERE NOT EXISTS(select 1 from TABLE_NAME where MyId=xxxx); 

La primera consulta simplemente actualiza el campo que necesita, si existe el MyID. La segunda inserta la fila en db si MyId no existe.

El resultado es que solo una de las consultas se ejecuta en su db.

+2

Si su versión de DB2 tiene 'MERGE', prefiera eso - ayudará a eliminar cierta concurrencia potencial cuestiones. Sin embargo, no etiquetaría automáticamente a este "más simple"; tiene sobrecarga adicional al tratar con dos declaraciones (que deben mantenerse sincronizadas), y realmente no resuelve la posibilidad de un proceso diferente al insertar la fila entre el 'UPDATE' y su propio' INSERT' ... –

+1

Esa declaración 'insert' es sintácticamente incorrecta. – mustaccio

11

Encontré este hilo porque realmente necesitaba una línea para DB2 INSERT OR UPDATE.

Parece que la sintaxis siguiente funciona, sin necesidad de una tabla temporal separada.

Funciona mediante el uso de VALUES() para crear una estructura de tabla. El SELECT * parece superávit en mi humilde opinión, pero sin él obtengo errores de sintaxis.

MERGE INTO mytable AS mt USING (
    SELECT * FROM TABLE (
     VALUES 
      (123, 'text') 
    ) 
) AS vt(id, val) ON (mt.id = vt.id) 
WHEN MATCHED THEN 
    UPDATE SET val = vt.val 
WHEN NOT MATCHED THEN 
    INSERT (id, val) VALUES (vt.id, vt.val) 
; 

si tiene que insertar más de una fila, la parte VALORES puede repetirse sin tener que duplicar el resto.

VALUES 
    (123, 'text'), 
    (456, 'more') 

El resultado es una única instrucción que puede insertar o actualizar una o varias filas presumiblemente como una operación atómica.

+0

Existe la posibilidad de que desee utilizar el nombre 'SELECT 'value' FROM SYSIBM.SYSDUMMY1' en lugar del' SELECT * FROM TABLE VALUES' – tgdn

Cuestiones relacionadas