오라클 12에서 기본 키를 위반합니다.SCD2 한 패스 병합 내가 치수 유형 2.</p> <p>그것은 고유 제한 조건없이 테이블에 완벽하게 작동 변경 천천히 historize하는 이럴 매우 빠른 원 - 패스 병합 문을 생각 몇 시간 후
대부분 고유 한 제약 조건이있는 테이블에서도 작동합니다. 하지만 때로는 (보통 역사가 바뀌면) ORA-00001 오류가 발생합니다. 이는 고유 한 제약 조건 위반입니다. 물론 두 가지 방법이 있지만 작동은 느리다는 것을 알고 있습니다.
내 생각에 오라클은 때때로 TH_Valid_To_Date를 복제하는 INSERT UPDATE를 잠깐 동안 수행합니다.
아이디어를 피하는 방법 (기본 키를 유지하면서)?
소스 테이블 :
CREATE TABLE TESTS
(
T_Key_1 NUMBER(38,0) DEFAULT -1 NOT NULL ENABLE /* */
,T_Key_2 NUMBER(38,0) DEFAULT -1 NOT NULL ENABLE /* */
,Text_Value VARCHAR2(100) /* */
,Number_Value NUMBER(38,0) DEFAULT -1 NOT NULL ENABLE /* */
,Amount NUMBER /* */
,CONSTRAINT T_PK PRIMARY KEY (T_Key_1, T_Key_2) /* Primární klíč */
)
;
역사 테이블 :
CREATE TABLE TEST_HISTORY
(
T_Key_1 NUMBER(38,0) DEFAULT -1 NOT NULL
,T_Key_2 NUMBER(38,0) DEFAULT -1 NOT NULL
,Text_Value VARCHAR2(100)
,Number_Value NUMBER(38,0) DEFAULT -1 NOT NULL
,Amount NUMBER
,TH_Valid_From_Date DATE DEFAULT to_date('1000-01-01','yyyy-mm-dd') NOT NULL /* SCD2 - Start of validity of record. */
,TH_Valid_To_Date DATE DEFAULT to_date('3000-01-01','yyyy-mm-dd') NOT NULL /* SCD2 - End of validity of record. */
,CONSTRAINT TH_PK PRIMARY KEY (T_Key_1, T_Key_2, TH_Valid_To_Date) using index local
)
/** Physical Options **************************************************************************************************/
partition by range (TH_Valid_To_Date) interval (NUMTOYMINTERVAL (1, 'MONTH'))
(partition P_10000000 values less than (TO_DATE ('01-01-1000', 'DD-MM-YYYY')))
ENABLE ROW MOVEMENT
;
병합 :
MERGE INTO (SELECT * FROM TEST_HISTORY WHERE TH_Valid_To_Date = to_date('3000-01-01','yyyy-mm-dd')) Hst /*change only current records which are identified by TH_Valid_To_Date = to_date('3000-01-01','yyyy-mm-dd') */
USING (
SELECT * FROM (
SELECT NVL(Src.T_Key_1, Dst.T_Key_1) AS T_Key_1
,NVL(Src.T_Key_2, Dst.T_Key_2) AS T_Key_2
,Src.Text_Value
,Src.Number_Value
,Src.Amount
,CASE WHEN Src.T_Key_1 is null THEN 'D' /*delete*/
WHEN Dst.T_Key_1 is null THEN 'I' /*insert*/
WHEN (Src.Text_Value=Dst.Text_Value OR (Src.Text_Value is null AND Dst.Text_Value is null))
AND (Src.Number_Value=Dst.Number_Value OR (Src.Number_Value is null AND Dst.Number_Value is null))
AND (Src.Amount=Dst.Amount OR (Src.Amount is null AND Dst.Amount is null))
THEN 'X' /*no change*/
ELSE 'U' /*update*/ END AS Operation
FROM TESTS Src
FULL JOIN (SELECT * FROM TEST_HISTORY WHERE TH_Valid_To_Date = to_date('3000-01-01','yyyy-mm-dd')) Dst
ON (Src.T_Key_1 = Dst.T_Key_1 AND Src.T_Key_2 = Dst.T_Key_2)
)
INNER JOIN (SELECT LEVEL AS duplication FROM DUAL CONNECT BY LEVEL BETWEEN 1 AND 2) ON (duplication=1 OR Operation='U') /*need to duplicate update records so that they can go to both matched and not matched parts*/
WHERE Operation<>'X'
) Act
ON (Act.T_Key_1 = Hst.T_Key_1 AND Act.T_Key_2 = Hst.T_Key_2 AND Act.duplication=1 AND Act.operation<>'I')
WHEN MATCHED THEN UPDATE
SET
TH_Valid_To_Date = p_Load_Date - 1,
WHERE Hst.TH_Valid_To_Date = to_date('3000-01-01','yyyy-mm-dd')
WHEN NOT MATCHED THEN INSERT /*+ append */
(
T_Key_1
,T_Key_2
,Text_Value
,Number_Value
,Amount
,TH_Valid_From_Date /*Auditní sloupec*/
,TH_Valid_To_Date /*Auditní sloupec*/
) VALUES (
Act.T_Key_1
,Act.T_Key_2
,Act.Text_Value
,Act.Number_Value
,Act.Amount
,p_Load_Date /*Auditní sloupec*/
,to_date('3000-01-01','yyyy-mm-dd') /*Auditní sloupec*/
)
;
브라이언, 귀하의 사례가 다른 것 같습니다. 원본 테이블에 고유 한 레코드가 있습니다. 병합 테이블의 고유성은 기본 키에 추가 된 TH_Valid_To_Date 열에 의해 보장됩니다. – Redford
병합 전에 표를로드 할 때 코드를 추가하십시오. 테스트 데이터를 보지 않고는 더 이상 지원할 수 없습니다. –
나는 그렇게 할 수 없다. 위에 표시된 테스트는 실제 사례의 단순화입니다. 실제 TESTS 테이블에는 14M 개의 행이 있고 TEST_HISTORY에는 53M 개의 행이 있습니다. 매일 병합 성명을 통해 변경된 기록 테이블에로드 된 레코드는 보통 50,000 개 미만입니다. 그것은 잘 작동합니다. 그러나 가끔씩 모든 14M 행이 크게 변경되고 기본 키 위반이 발생합니다. – Redford