[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.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.병합 문은 두 테이블간에 데이터를 병합합니다. 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.나는 비슷한 일을하고 싶었 기 때문에 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.예외 검사없이 또 다른 대안 :
예외 검사없이 또 다른 대안 :
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.
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.지금까지 주어진 답변 없음은 팀 실베스터의 발언에서 지적 동시 액세스의 얼굴에서 안전하지 않으며, 인종의 경우에 예외를 발생합니다. 이 문제를 해결하려면, 삽입 / 업데이트 콤보는 예외의 경우에는 모든 일이 시도됩니다 그래서, 루프 문 어떤 종류의에 싸여해야합니다.
지금까지 주어진 답변 없음은 팀 실베스터의 발언에서 지적 동시 액세스의 얼굴에서 안전하지 않으며, 인종의 경우에 예외를 발생합니다. 이 문제를 해결하려면, 삽입 / 업데이트 콤보는 예외의 경우에는 모든 일이 시도됩니다 그래서, 루프 문 어떤 종류의에 싸여해야합니다.
예를 들어, 여기에 동시에 실행할 때 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.이 속는 값이 필요 제외하고 나는 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.제안 두 솔루션에 대한 참고 사항 :
제안 두 솔루션에 대한 참고 사항 :
1) 삽입, 예외가 다음 업데이트 할 경우,
또는
2) 업데이트,하다면 SQL % ROWCOUNT = 0 다음 삽입
삽입 또는 업데이트 여부의 문제는 첫째도 응용 프로그램에 따라 다릅니다. 당신은 더 많은 삽입 이상의 업데이트를 기대하고 있습니까? 성공 가능성이 가장 높은 하나는 가셔야합니다.
잘못된 하나를 선택하면 불필요한 인덱스의 무리 읽기 얻을 것이다. 아니 거대한 거래하지만 여전히 뭔가 생각합니다.
-
==============================
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.복사 및 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.이 시도,
이 시도,
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.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;
from https://stackoverflow.com/questions/237327/oracle-how-to-upsert-update-or-insert-into-a-table by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] WHERE 절에 열 별칭을 참조 (0) | 2020.03.12 |
---|---|
[SQL] WHERE HAVING 대 (0) | 2020.03.12 |
[SQL] 테스트에 가장 좋은 방법은 행은 MySQL의 테이블에 존재하는 경우 (0) | 2020.03.12 |
[SQL] 차이 사이의 가입 및 INNER는 가입 (0) | 2020.03.12 |
[SQL] 준비된 문을 사용하여 변수 열 이름 (0) | 2020.03.12 |