복붙노트

[SQL] 오라클 (? 테이블에 갱신 또는 삽입) 방법 UPSERT에

SQL

오라클 (? 테이블에 갱신 또는 삽입) 방법 UPSERT에

UPSERT 작업 테이블이 이미 데이터와 일치하는 행이 여부에 따라 테이블의 업데이트 또는 삽입 행을, 중 :

if table t has a row exists that has key X:
    update t set mystuff... where mykey=X
else
    insert into t mystuff...

오라클은 특정의 UPSERT 문을 가지고 있지 않기 때문에,이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

해결법

  1. ==============================

    1.MERGE에 대한 대안 (이하 "옛날 방식") :

    MERGE에 대한 대안 (이하 "옛날 방식") :

    begin
       insert into t (mykey, mystuff) 
          values ('X', 123);
    exception
       when dup_val_on_index then
          update t 
          set    mystuff = 123 
          where  mykey = 'X';
    end;   
    
  2. ==============================

    2.병합 문은 두 테이블간에 데이터를 병합합니다. DUAL 사용 우리는이 명령을 사용할 수 있습니다. 이 동시 액세스로부터 보호되지 않습니다.

    병합 문은 두 테이블간에 데이터를 병합합니다. DUAL 사용 우리는이 명령을 사용할 수 있습니다. 이 동시 액세스로부터 보호되지 않습니다.

    create or replace
    procedure ups(xa number)
    as
    begin
        merge into mergetest m using dual on (a = xa)
             when not matched then insert (a,b) values (xa,1)
                 when matched then update set b = b+1;
    end ups;
    /
    drop table mergetest;
    create table mergetest(a number, b number);
    call ups(10);
    call ups(10);
    call ups(20);
    select * from mergetest;
    
    A                      B
    ---------------------- ----------------------
    10                     2
    20                     1
    
  3. ==============================

    3.나는 비슷한 일을하고 싶었 기 때문에 PL / SQL에있는 위의 듀얼 예 좋았어요,하지만 난 그것을 클라이언트 측을 원했다 ... 그래서 여기에 SQL 나는 약간의 C #에서 직접 유사한 문을 전송하는 데 사용됩니다

    나는 비슷한 일을하고 싶었 기 때문에 PL / SQL에있는 위의 듀얼 예 좋았어요,하지만 난 그것을 클라이언트 측을 원했다 ... 그래서 여기에 SQL 나는 약간의 C #에서 직접 유사한 문을 전송하는 데 사용됩니다

    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" )
    

    그러나 C #을 관점에서이 업데이트를하고 영향을받는 행이 0 인 경우보고하고 있다면 삽입하는 것보다 느린로 제공합니다.

  4. ==============================

    4.예외 검사없이 또 다른 대안 :

    예외 검사없이 또 다른 대안 :

    UPDATE tablename
        SET val1 = in_val1,
            val2 = in_val2
        WHERE val3 = in_val3;
    
    IF ( sql%rowcount = 0 )
        THEN
        INSERT INTO tablename
            VALUES (in_val1, in_val2, in_val3);
    END IF;
    
  5. ==============================

    5.

        
    INSERT INTO mytable (id1, t1) 
      SELECT 11, 'x1' FROM DUAL 
      WHERE NOT EXISTS (SELECT id1 FROM mytble WHERE id1 = 11); 
    
    UPDATE mytable SET t1 = 'x1' WHERE id1 = 11;
    
  6. ==============================

    6.지금까지 주어진 답변 없음은 팀 실베스터의 발언에서 지적 동시 액세스의 얼굴에서 안전하지 않으며, 인종의 경우에 예외를 발생합니다. 이 문제를 해결하려면, 삽입 / 업데이트 콤보는 예외의 경우에는 모든 일이 시도됩니다 그래서, 루프 문 어떤 종류의에 싸여해야합니다.

    지금까지 주어진 답변 없음은 팀 실베스터의 발언에서 지적 동시 액세스의 얼굴에서 안전하지 않으며, 인종의 경우에 예외를 발생합니다. 이 문제를 해결하려면, 삽입 / 업데이트 콤보는 예외의 경우에는 모든 일이 시도됩니다 그래서, 루프 문 어떤 종류의에 싸여해야합니다.

    예를 들어, 여기에 동시에 실행할 때 Grommit의 코드가 안전하게 만들 수있는 루프로 포장하는 방법은 다음과 같습니다

    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. 트랜잭션 모드 SERIALIZABLE에서, 내가 BTW 권장하지 않는 경우에 실행될 수 있습니다 ORA-08177은 : 대신 트랜잭션 예외에 대한 액세스를 직렬화 할 수 없습니다.

  7. ==============================

    7.이 속는 값이 필요 제외하고 나는 Grommit 대답하고 싶습니다. http://forums.devshed.com/showpost.php?p=1182653&postcount=2 : 그것은 한 번 게재 할 수있는 위치 나는 해결책을 발견

    이 속는 값이 필요 제외하고 나는 Grommit 대답하고 싶습니다. http://forums.devshed.com/showpost.php?p=1182653&postcount=2 : 그것은 한 번 게재 할 수있는 위치 나는 해결책을 발견

    MERGE INTO KBS.NUFUS_MUHTARLIK B
    USING (
        SELECT '028-01' CILT, '25' SAYFA, '6' KUTUK, '46603404838' MERNIS_NO
        FROM DUAL
    ) E
    ON (B.MERNIS_NO = E.MERNIS_NO)
    WHEN MATCHED THEN
        UPDATE SET B.CILT = E.CILT, B.SAYFA = E.SAYFA, B.KUTUK = E.KUTUK
    WHEN NOT MATCHED THEN
        INSERT (  CILT,   SAYFA,   KUTUK,   MERNIS_NO)
        VALUES (E.CILT, E.SAYFA, E.KUTUK, E.MERNIS_NO); 
    
  8. ==============================

    8.제안 두 솔루션에 대한 참고 사항 :

    제안 두 솔루션에 대한 참고 사항 :

    1) 삽입, 예외가 다음 업데이트 할 경우,

    또는

    2) 업데이트,하다면 SQL % ROWCOUNT = 0 다음 삽입

    삽입 또는 업데이트 여부의 문제는 첫째도 응용 프로그램에 따라 다릅니다. 당신은 더 많은 삽입 이상의 업데이트를 기대하고 있습니까? 성공 가능성이 가장 높은 하나는 가셔야합니다.

    잘못된 하나를 선택하면 불필요한 인덱스의 무리 읽기 얻을 것이다. 아니 거대한 거래하지만 여전히 뭔가 생각합니다.

  9. ==============================

    9.나는 몇 년의 첫 번째 코드 샘플을 사용했습니다. 공지 사항 NOTFOUND보다는 수입니다.

    나는 몇 년의 첫 번째 코드 샘플을 사용했습니다. 공지 사항 NOTFOUND보다는 수입니다.

    UPDATE tablename SET val1 = in_val1, val2 = in_val2
        WHERE val3 = in_val3;
    IF ( sql%notfound ) THEN
        INSERT INTO tablename
            VALUES (in_val1, in_val2, in_val3);
    END IF;
    

    아래 코드는 아마도 새롭게 개선 된 코드

    MERGE INTO tablename USING dual ON ( val3 = in_val3 )
    WHEN MATCHED THEN UPDATE SET val1 = in_val1, val2 = in_val2
    WHEN NOT MATCHED THEN INSERT 
        VALUES (in_val1, in_val2, in_val3)
    

    제 1 실시 예에 관한 업데이트 인덱스를 검색한다. 그것은 올바른 행을 업데이트하기 위해에 있습니다. 오라클은 암시 적 커서를 열고, 우리가 키가 존재하지 않는 경우 삽입 만 일어날 것이라는 점을 알 수 있도록 우리는 해당 삽입을 포장하는 데 사용합니다. 그러나 삽입 독립적 인 명령이며 두 번째 검색을 할 수 있습니다. 나는 병합 명령의 내부 동작을 모르지만 명령이 하나의 단위이기 때문에, 오라클은 하나의 인덱스 검색으로 올바른 삽입 또는 업데이트를 실행있을 수 있습니다.

    나는 당신이 어떤 처리 수단이 일부 테이블에서 데이터를 복용하고 테이블을 업데이트 가능하게 삽입하거나 행을 삭제하는 것을 수행해야 할 때 병합 더 나은 생각합니다. 구문이 더 일반적이기 때문에 그러나 단일 행의 경우에, 당신은 첫 번째 경우를 고려할 수 있습니다.

  10. ==============================

    10.복사 및 MERGE와 다른에 하나 개의 테이블을 upserting에 대한 예를 붙여 넣습니다

    복사 및 MERGE와 다른에 하나 개의 테이블을 upserting에 대한 예를 붙여 넣습니다

    CREATE GLOBAL TEMPORARY TABLE t1
        (id VARCHAR2(5) ,
         value VARCHAR2(5),
         value2 VARCHAR2(5)
         )
      ON COMMIT DELETE ROWS;
    
    CREATE GLOBAL TEMPORARY TABLE t2
        (id VARCHAR2(5) ,
         value VARCHAR2(5),
         value2 VARCHAR2(5))
      ON COMMIT DELETE ROWS;
    ALTER TABLE t2 ADD CONSTRAINT PK_LKP_MIGRATION_INFO PRIMARY KEY (id);
    
    insert into t1 values ('a','1','1');
    insert into t1 values ('b','4','5');
    insert into t2 values ('b','2','2');
    insert into t2 values ('c','3','3');
    
    
    merge into t2
    using t1
    on (t1.id = t2.id) 
    when matched then 
      update set t2.value = t1.value,
      t2.value2 = t1.value2
    when not matched then
      insert (t2.id, t2.value, t2.value2)  
      values(t1.id, t1.value, t1.value2);
    
    select * from t2
    

    결과:

  11. ==============================

    11.이 시도,

    이 시도,

    insert into b_building_property (
      select
        'AREA_IN_COMMON_USE_DOUBLE','Area in Common Use','DOUBLE', null, 9000, 9
      from dual
    )
    minus
    (
      select * from b_building_property where id = 9
    )
    ;
    
  12. ==============================

    12.http://www.praetoriate.com/oracle_tips_upserts.htm에서 :

    http://www.praetoriate.com/oracle_tips_upserts.htm에서 :

    "오라클에서는, UPSERT은 하나의 문에서이 작업을 수행 할 수 있습니다"

    INSERT
    FIRST WHEN
       credit_limit >=100000
    THEN INTO
       rich_customers
    VALUES(cust_id,cust_credit_limit)
       INTO customers
    ELSE
       INTO customers SELECT * FROM new_customers;
    
  13. from https://stackoverflow.com/questions/237327/oracle-how-to-upsert-update-or-insert-into-a-table by cc-by-sa and MIT license