web-dev-qa-db-fra.com

DB2 a-t-il une instruction «insérer ou mettre à jour»?

Depuis mon code (Java), je veux m'assurer qu'une ligne existe dans la base de données (DB2) après l'exécution de mon code.

Mon code fait maintenant un select et si aucun résultat n'est renvoyé il fait un insert. Je n'aime vraiment pas ce code car il m'expose à des problèmes de concurrence lors de l'exécution dans un environnement multi-thread.

Ce que je voudrais faire est de mettre cette logique dans DB2 au lieu de dans mon Java. DB2 a-t-il un insert-or-update déclaration? Ou quelque chose comme ça que je peux utiliser?

Par exemple:

insertupdate into mytable values ('myid')

Une autre façon de le faire serait probablement de toujours faire l'insertion et de capturer "la clé primaire SQL-code -803 existe déjà", mais j'aimerais éviter cela si possible.

37
Mikael Eriksson

Oui, DB2 a l'instruction MERGE, qui fera un UPSERT (mise à jour ou insertion).

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

Voir:

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

https://www.ibm.com/support/knowledgecenter/en/SS6NHC/com.ibm.swg.im.dashdb.sql.ref.doc/doc/r0010873.html

https://www.ibm.com/developerworks/community/blogs/SQLTips4DB2LUW/entry/merge?lang=en

41
Winston Smith

J'ai trouvé ce fil parce que j'avais vraiment besoin d'une doublure pour DB2 INSERT OR UPDATE.

La syntaxe suivante semble fonctionner, sans nécessiter de table temporaire distincte.

Il fonctionne en utilisant VALUES () pour créer une structure de table. Le SELECT * semble excédentaire à mon humble avis mais sans lui j'obtiens des erreurs de syntaxe.

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 vous devez insérer plus d'une ligne, la partie VALUES peut être répétée sans avoir à dupliquer le reste.

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

Le résultat est une seule instruction qui peut INSÉRER OR METTRE À JOUR une ou plusieurs lignes vraisemblablement comme une opération atomique.

16
teknopaul

Nous espérons que cette réponse répondra pleinement à la requête de MrSimpleMind dans se-update-and-insert-in-same-query et fournira un exemple simple et fonctionnel de l'instruction DB2 MERGE avec un scénario d'insertion ET mise à jour en une seule fois (l'enregistrement avec l'ID 2 est mis à jour et l'ID d'enregistrement 3 inséré).

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;
11
CupOfTea

Une autre façon est d'exécuter ces 2 requêtes. C'est plus simple que de créer une instruction 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 première requête met simplement à jour le champ dont vous avez besoin, si le MyId existe. Le second insère la ligne dans db si MyId n'existe pas.

Le résultat est qu'une seule des requêtes est exécutée dans votre base de données.

2
Felipe