Oracle: how to UPSERT (update or insert into a table?)

后端 未结 12 1566
南旧
南旧 2020-11-22 07:18

The UPSERT operation either updates or inserts a row in a table, depending if the table already has a row that matches the data:

if table t has a row exists          


        
12条回答
  •  萌比男神i
    2020-11-22 08:08

    None of the answers given so far is safe in the face of concurrent accesses, as pointed out in Tim Sylvester's comment, and will raise exceptions in case of races. To fix that, the insert/update combo must be wrapped in some kind of loop statement, so that in case of an exception the whole thing is retried.

    As an example, here's how Grommit's code can be wrapped in a loop to make it safe when run concurrently:

    PROCEDURE MyProc (
     ...
    ) IS
    BEGIN
     LOOP
      BEGIN
        MERGE INTO Employee USING dual ON ( "id"=2097153 )
          WHEN MATCHED THEN UPDATE SET "last"="smith" , "name"="john"
          WHEN NOT MATCHED THEN INSERT ("id","last","name") 
            VALUES ( 2097153,"smith", "john" );
        EXIT; -- success? -> exit loop
      EXCEPTION
        WHEN NO_DATA_FOUND THEN -- the entry was concurrently deleted
          NULL; -- exception? -> no op, i.e. continue looping
        WHEN DUP_VAL_ON_INDEX THEN -- an entry was concurrently inserted
          NULL; -- exception? -> no op, i.e. continue looping
      END;
     END LOOP;
    END; 
    

    N.B. In transaction mode SERIALIZABLE, which I don't recommend btw, you might run into ORA-08177: can't serialize access for this transaction exceptions instead.

提交回复
热议问题