2010-05-26 2 views
3

에 대한 실행되지 :오라클 - 업데이트의 UPSERT 내가 업데이 트를 다음 또는 순간에 오라클 문을 삽입 사용하고 수정되지 않은 값

BEGIN 
    UPDATE DSMS 
    SET SURNAME = :SURNAME 
    WHERE DSM = :DSM; 
    IF (SQL%ROWCOUNT = 0) THEN 
    INSERT INTO DSMS 
     (DSM, SURNAME) 
    VALUES 
     (:DSM, :SURNAME); 
    END IF; 
END; 

이 데이터가 동일한 경우 업데이트 문이 더미 업데이트를 수행하는 것을 제외하고 잘 실행 제공된 매개 변수 값으로 사용하십시오. 정상적인 상황에서 더미 업데이트는 신경 쓰지 않지만 테이블의 트리거를 사용하여 업데이트 된 레코드를 캡처하고이 레코드를 자주 실행하면 트리거 및 트리거에 막대한 트래픽이 발생한다는 것을 의미하는 복제/동기화 시스템이이 테이블 위에 구축됩니다. 동기 시스템.

다음 코드를 사용하지 않고 업데이트 구문이 레코드를 업데이트하지 못하도록이 코드를 재구성하는 방법이 있습니까?이 코드에서는 매끄럽지 않고 어쩌면이 작업에 가장 효율적이지 않은 체크 코드를 사용하지 않습니까?

DECLARE 
    CNT NUMBER; 
BEGIN 
    SELECT COUNT(1) INTO CNT FROM DSMS WHERE DSM = :DSM; 
    IF SQL%FOUND THEN 
    UPDATE DSMS 
     SET SURNAME = :SURNAME 
    WHERE DSM = :DSM 
     AND SURNAME != :SURNAME; 
    ELSE 
    INSERT INTO DSMS 
     (DSM, SURNAME) 
    VALUES 
     (:DSM, :SURNAME); 
    END IF; 
END; 

는 또한 문에 병합 사용했지만, 값이 (갱신 아무것도 수정하지 않고 삽입이 실행되지만, PK 위반이 발생) 수정되지 않은 경우는 업데이트가 작동하지 않습니다. 샘플 INTO

전체 MERGE :

CREATE TABLE DSMS(
    dsm VARCHAR2(10) NOT NULL PRIMARY KEY, 
    surname VARCHAR2(10) NOT NULL 
); 
> Table created 

-- :DSM = 'xx', :SURNAME = 'xx' 
MERGE INTO DSMS D 
USING (SELECT :DSM  AS DSM, 
       :SURNAME AS SURNAME 
     FROM DUAL) V 
ON (D.DSM = V.DSM) 
WHEN MATCHED THEN 
    UPDATE 
    SET SURNAME = V.SURNAME 
    WHERE D.SURNAME <> V.SURNAME 
WHEN NOT MATCHED THEN 
    INSERT (DSM, SURNAME) 
    VALUES (V.DSM, V.SURNAME); 

> Ok - record inserted 

-- :DSM = 'xx', :SURNAME = 'xx' 
MERGE INTO DSMS D 
USING (SELECT :DSM  AS DSM, 
       :SURNAME AS SURNAME 
     FROM DUAL) V 
ON (D.DSM = V.DSM) 
WHEN MATCHED THEN 
    UPDATE 
    SET SURNAME = V.SURNAME 
    WHERE D.SURNAME <> V.SURNAME 
WHEN NOT MATCHED THEN 
    INSERT (DSM, SURNAME) 
    VALUES (V.DSM, V.SURNAME); 

> ORA-00001 - Unique constraint violated (PK violation) 

그것은 UPDATE를 사용하는 오라클처럼 보이는 ... SQL의 %의 ROWCOUNT = 0 THEN 삽입하면 ... 내부 절에 병합을 검색 하시나요? 두 번째 MERGE INTO 문은 업데이트가 아무 것도 업데이트하지 않으므로 INSERT가 실행되므로 PK 위반이 발생합니다. 행이 이미 존재하기 때문에 값이 변경되지 않았기 때문입니다.

+0

샘플에서'DSMS'을'TestMerge'로 대체하면 두 문장 모두 저에게 잘 돌아갑니다. – Quassnoi

+0

@Quassnoi : 일부 Oracle DB 버전의 Oracle MERGE INTO 구현에서 버그에 대한 정보를 발견했습니다. 병합 명령을 두 번 실행하면 PK 위반이 발생하기 때문에 일부 버그가 발생할 수 있습니다. 샘플을 성공적으로 실행 한 OraDB 버전은 무엇입니까? 나는 10.2.0.1.0에있다 ... – Buthrakaur

+0

나는 버전'10.2.0.1.0'도 실행 중이다. 여러분이 생성 한 샘플 테이블은'TestMerge'라고 불리우지 만,'MERGE' 통계에서는'DSMS' 테이블을 사용합니다 :'MERGE INTO DSMS D ...'. – Quassnoi

답변

4
MERGE 
INTO dsms d 
USING (
     SELECT :DSM AS dsm, :SURNAME AS surname, :FIRSTNAME AS firstname, :VALID AS valud 
     FROM dual 
     ) v 
ON  (d.dsm = q.dsm) 
WHEN MATCHED THEN 
UPDATE 
SET  SURNAME = v.SURNAME, FIRSTNAME = v.FIRSTNAME, VALID = v.VALID 
WHERE d.surname <> v.surname 
     OR d.firstname <> v.firstname 
     OR d.valid <> v.valid 
WHEN NOT MATCHED THEN 
INSERT 
INTO (SURNAME, FIRSTNAME, VALID) 
VALUES (SURNAME, FIRSTNAME, VALID) 

당신은 당신의 필드 NULL 값을 사용할 경우 추가 NULL 검사를 추가해야 할 수 있습니다.

+0

감사합니다. 불행히도 행이 이미 존재하지만 값이 같으면 삽입이 실행되고 PK 위반 예외가 발생하면이 작업이 수행되지 않습니다. 나는 "WHERE D.SURNAME <> V.SURNAME ..."을 INTO 절에 추가하려고 시도했지만 "ORA-38102 INSERT WHERE"열이 잘못되었습니다. – Buthrakaur

+0

@Buth : 확실히, 내 잘못. 지금 시도하십시오. – Quassnoi

+0

DSM 필드가 기본 키이므로 DSM이 null 일 수 없으므로 삽입이 실패합니다. ... – Buthrakaur

2

헤드를 끌 수 있습니다. 업데이트에 대한 삽입의 비율에 따라 다르지만 많은 업데이트로 인해 많은 삽입이 실패하게됩니다.

BEGIN 
    INSERT INTO DSMS 
     (DSM, SURNAME) 
    VALUES 
     (:DSM, :SURNAME); 
EXCEPTION WHEN DUP_VAL_ON_INDEX THEN 
    UPDATE DSMS 
     SET SURNAME = :SURNAME 
    WHERE DSM = :DSM 
     AND SURNAME != :SURNAME; 
END; 
+0

당신 말이 맞아요. 좋은 생각입니다. 비록 대부분의 문장이 내 시나리오에서 어떤 행 (값이 변하지 않을 것입니다)을 수정하지 않고 업데이트를 실행하는 것으로 끝나기는하지만 최적의 솔루션이 아닐 수도 있습니다. 나는 그것을 시험해 볼 것이다. 감사. – Buthrakaur