Nach einiger Zeit dachte ich imho recht schnell einen Pass merge Anweisung langsam historisieren Bemaßungstyp Ändern 2.SCD2 ein Pass merge verletzt Primärschlüssel in Oracle 12
Es funktioniert perfekt auf Tabellen ohne eindeutige Einschränkung.
Meistens funktioniert es auch auf Tabellen mit eindeutiger Einschränkung. Aber manchmal (normalerweise, wenn die Änderung in der Geschichte größer ist), erhalte ich den Fehler ORA-00001, eine eindeutige Einschränkung der Beschränkung. Natürlich weiß ich, dass es Zwei-Durchlauf-Methoden gibt, die funktionieren, aber sie sind langsamer.
Meine einzige Vermutung ist, dass Oracle manchmal die INSERT vor UPDATE, die den TH_Valid_To_Date für einen Moment dupliziert.
Irgendwelche Ideen, wie man es vermeiden kann (während der Primärschlüssel beibehalten wird)?
Quelltabelle:
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íč */
)
;
Geschichte Tabelle:
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:
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*/
)
;
Brian, Ihr Fall scheint mir anders. Ich habe eindeutige Datensätze in der Quellentabelle. Die Eindeutigkeit in der Zusammenführungstabelle wird durch die TH_Valid_To_Date-Spalte sichergestellt, die dem Primärschlüssel hinzugefügt wird. – Redford
Bitte fügen Sie Code zum Laden der Tabellen vor dem Zusammenführen hinzu. Ohne Ihre Testdaten zu sehen, kann ich Ihnen nicht weiterhelfen. –
Ich kann das wahrscheinlich nicht tun. Der oben gezeigte Test ist eine Vereinfachung des realen Falls. Die echte TESTS-Tabelle hat 14M Zeilen und TEST_HISTORY hat 53M Zeilen. Jeden Tag werden normalerweise weniger als 50k Datensätze geändert und über die Merge-Anweisung in die History-Tabelle geladen. Es funktioniert gut. Hin und wieder tritt jedoch eine große Änderung aller 14M-Zeilen auf, und dann tritt die Primärschlüsselverletzung auf. – Redford