Oracle: 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...
Oracle에는 특정 UPSERT 문구가 없기 때문에 이를 위한 가장 좋은 방법은 무엇입니까?
MERGE 문은 두 테이블 간의 데이터를 병합합니다.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
위의 PL/SQL에 있는 듀얼 예시는 매우 좋았습니다.왜냐하면 저는 비슷한 일을 하고 싶었지만 클라이언트 측에서 하고 싶었기 때문입니다.여기 C#에서 직접 유사한 스테이트먼트를 전송하기 위해 사용한SQL이 있습니다.
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인지 확인하고 해당 행이 0인지 삽입되었는지 여부를 확인하는 것보다 속도가 느려집니다.
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;
예외 검사를 사용하지 않는 다른 대안:
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;
- 없는 경우 삽입
- 업데이트:
마이테이블에 삽입(id1, t1)듀얼에서 11, 'x1' 선택존재하지 않는 곳(mytble에서 id1 WHERE 1 = 11); 업데이트 mytable SET t1 = 'x1' WHERE ID1 = 11;
팀 실베스터의 코멘트에서 지적된 바와 같이 동시 접속이 가능한 상황에서 지금까지 나온 답변 중 어느 것도 안전하지 않으며, 레이스의 경우 예외를 제기할 것이다.이 문제를 해결하려면 insert/update 콤보를 일종의 루프 스테이트먼트로 감싸야 합니다.그러면 예외 발생 시 모든 것을 재시도할 수 있습니다.
예를 들어, 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
ORA-08177: 이 트랜잭션 예외에 대한 액세스를 직렬화할 수 없습니다.
그로밋이 대답하고 싶은데, 다만 중복된 값이 필요해요.한 번 표시되는 솔루션을 찾았습니다.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);
난 몇 년 동안 첫 번째 코드 샘플을 사용해왔어.카운트가 아니라 not found(찾을 수 없음)입니다.
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)
첫 번째 예에서는 업데이트가 인덱스를 검색합니다.오른쪽 행을 업데이트하려면 이 작업을 수행해야 합니다.Oracle은 암묵적인 커서를 열고 해당 삽입을 래핑하기 위해 이 커서를 사용합니다.그러면 삽입은 키가 존재하지 않는 경우에만 이루어집니다.그러나 insert는 독립된 명령어이므로 두 번째 검색을 수행해야 합니다.merge 명령어의 내부 동작은 알 수 없지만 명령어가 단일 단위이기 때문에 Oracle은 단일 인덱스 룩업으로 올바른 삽입 또는 업데이트를 실행할 수 있습니다.
일부 테이블에서 데이터를 가져와 테이블을 업데이트하거나 행을 삽입하거나 삭제하는 등의 처리가 필요한 경우에는 병합이 더 낫다고 생각합니다.단, 단일 행의 경우 구문이 더 일반적이기 때문에 첫 번째 경우를 고려할 수 있습니다.
다음 두 가지 솔루션에 대한 참고 사항:
1) 예외인 경우 삽입 후 갱신한다.
또는
2) sql%rowcount = 0인 경우 업데이트한 후
먼저 삽입할지 업데이트할지 여부도 애플리케이션에 따라 달라집니다.추가 삽입 또는 추가 업데이트가 필요합니까?성공할 가능성이 가장 높은 사람이 먼저 가야 한다.
잘못된 항목을 선택하면 불필요한 색인 읽기가 많이 발생합니다.큰 문제는 아니지만 고려해야 할 사항입니다.
이거 드셔보세요.
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
)
;
http://www.praetoriate.com/oracle_tips_upserts.htm 에서 :
"Oracle9i에서는 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;
언급URL : https://stackoverflow.com/questions/237327/oracle-how-to-upsert-update-or-insert-into-a-table
'programing' 카테고리의 다른 글
json 문자를 열거형으로 역직렬화 (0) | 2023.03.06 |
---|---|
JWT를 저장하고 react를 사용하여 모든 요청과 함께 전송하려면 어떻게 해야 합니까? (0) | 2023.03.06 |
기능 컴포넌트 내의 ReactJS 라이프 사이클 방법 (0) | 2023.03.06 |
Microsoft Excel의 인셀과 루프 모두에서 정규 표현(Regex)을 사용하는 방법 (0) | 2023.03.06 |
입력 키에서 양식 제출 금지 (0) | 2023.03.06 |