0% found this document useful (1 vote)
3K views

Update SCD - SQL

This procedure updates a slowly changing dimension (SCD) table by comparing source and target records, identifying new, updated, and overwritten records, sorting them appropriately, and then inserting, updating, or overwriting records in the target table while tracking counts of each operation. Temporary arrays are used to store column lists and record sets for dynamic SQL generation.

Uploaded by

Jacek Adamowicz
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (1 vote)
3K views

Update SCD - SQL

This procedure updates a slowly changing dimension (SCD) table by comparing source and target records, identifying new, updated, and overwritten records, sorting them appropriately, and then inserting, updating, or overwriting records in the target table while tracking counts of each operation. Temporary arrays are used to store column lists and record sets for dynamic SQL generation.

Uploaded by

Jacek Adamowicz
Copyright
© Attribution Non-Commercial (BY-NC)
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
You are on page 1/ 5

CREATE OR REPLACE PROCEDURE update_scd(

pSrcTable VARCHAR2
,pNaturalKey VARCHAR2
,pTrgTable VARCHAR2
,pSurrogateKey VARCHAR2
,pSequence VARCHAR2
,pOverwriteCols VARCHAR2
,pVersionedCols VARCHAR2
,pStartTS VARCHAR2
,pEndTS VARCHAR2
,pCurrRecFlag VARCHAR2
,pNewRecordsCount OUT NUMBER
,pVersionedRecordsCount OUT NUMBER
,pOverwrittenRecordsCount OUT NUMBER ) IS
mNK dbms_utility.uncl_array;
mOvw dbms_utility.uncl_array;
mVer dbms_utility.uncl_array;
mAll dbms_utility.uncl_array;
mCode dbms_sql.varchar2s;
mItemCnt INTEGER;
PROCEDURE kod( pLinia VARCHAR2 ) IS
BEGIN
-- dbms_output.put_line( pLinia );
mCode( mCode.COUNT+1 ) := pLinia;
END;
PROCEDURE execute_code IS
mCursor INTEGER;
mRowCount NUMBER(9);
BEGIN
mCursor := dbms_sql.OPEN_CURSOR;
dbms_sql.PARSE(mCursor,mCode,1,mCode.COUNT,TRUE,dbms_sql.NATIVE);
dbms_sql.bind_variable(mCursor,'TOTAL_NEW_COUNT',pNewRecordsCount);
dbms_sql.bind_variable(mCursor,'TOTAL_OVW_COUNT',pOverwrittenRecordsCount);
dbms_sql.bind_variable(mCursor,'TOTAL_VER_COUNT',pVersionedRecordsCount);
mRowCount := dbms_sql.EXECUTE(mCursor);
dbms_sql.variable_value(mCursor,'TOTAL_NEW_COUNT',pNewRecordsCount);
dbms_sql.variable_value(mCursor,'TOTAL_OVW_COUNT',pOverwrittenRecordsCount);
dbms_sql.variable_value(mCursor,'TOTAL_VER_COUNT',pVersionedRecordsCount);
dbms_sql.CLOSE_CURSOR(mCursor);
END;

PROCEDURE formatuj_liste2(
pKolumny IN OUT NOCOPY dbms_utility.uncl_array
,pTemplate VARCHAR2
,pSeparator VARCHAR2
,pLimitChars NUMBER DEFAULT 60
,pLimitItems NUMBER DEFAULT 10
,pPrefix VARCHAR2 DEFAULT NULL
,pPostfix VARCHAR2 DEFAULT NULL
,pLinePrefix VARCHAR2 DEFAULT NULL) IS
linia VARCHAR2(255);
chunk VARCHAR2(255);
items NUMBER(5);
BEGIN
linia := pLinePrefix || pPrefix;
items := 0;
FOR i IN pKolumny.FIRST..pKolumny.LAST
LOOP
chunk := replace(pTemplate,'{COL}',pKolumny(i));
IF i < pKolumny.LAST THEN
chunk := chunk || pSeparator;
ELSE
chunk := chunk || pPostfix;
END IF;
IF length(linia) + length(chunk) > pLimitChars OR items=pLimitItems THEN
kod(linia);
linia := pLinePrefix;
items := 0;
END IF;
linia := linia || chunk;
items := items + 1;
END LOOP;
kod(linia);
END;

BEGIN
dbms_utility.COMMA_TO_TABLE(pNaturalKey,mItemCnt,mNK);
dbms_utility.COMMA_TO_TABLE(pOverwriteCols,mItemCnt,mOvw);
dbms_utility.COMMA_TO_TABLE(pVersionedCols,mItemCnt,mVer);
dbms_utility.COMMA_TO_TABLE(pNaturalKey||','||pVersionedCols||','||pOverwrit
eCols,mItemCnt,mAll);
mNK.DELETE(mNK.COUNT);
mOvw.DELETE(mOvw.COUNT);
mVer.DELETE(mVer.COUNT);
mAll.DELETE(mAll.COUNT);
kod('DECLARE');
kod(' CURSOR c IS');
kod(' SELECT');
formatuj_liste2(mAll,'src.{COL}',', ',75,10,'',', ',' ');
kod(' CASE');
kod(' WHEN trg.' || mNk(1) || ' IS NULL THEN ''I''');
formatuj_liste2(mVer,'(src.{COL}!=trg.{COL} OR (src.{COL} IS NULL AND trg.{C
OL} IS NOT NULL) OR (src.{COL} IS NOT NULL AND trg.{COL} IS NULL))',' OR ',250,1
,'WHEN ',' THEN ''V''',' ');
kod(' ELSE ''U''');
kod(' END oper_ind');
kod(' FROM ' || pSrcTable || ' src ');
kod(' LEFT JOIN ' || pTrgTable || ' trg ');
formatuj_liste2(mNK,'src.{COL}=trg.{COL}',' AND ',150,1,'ON ','','
');
kod(' AND trg.' || pCurrRecFlag || '=1');
kod(' WHERE trg.' || mNK(1) || ' IS NULL OR');
formatuj_liste2(mVer,'(src.{COL}!=trg.{COL} OR (src.{COL} IS NULL AND trg.{C
OL} IS NOT NULL) OR (src.{COL} IS NOT NULL AND trg.{COL} IS NULL))',' OR ',250,1
,'',' OR ',' ');
formatuj_liste2(mOvw,'(src.{COL}!=trg.{COL} OR (src.{COL} IS NULL AND trg.{C
OL} IS NOT NULL) OR (src.{COL} IS NOT NULL AND trg.{COL} IS NULL))',' OR ',250,1
,'','',' ');
kod(';');
kod('');
formatuj_liste2(mAll,'TYPE t{COL} IS TABLE OF ' || pTrgTable || '.{COL}%TYPE
INDEX BY BINARY_INTEGER;','',150,1,'','',' ');
kod(' TYPE tFlag IS TABLE OF CHAR(1) INDEX BY BINARY_INTEGER;');
kod('');
formatuj_liste2(mAll,'tr{COL} t{COL};','',150,1,'','',' ');
kod(' trOPER_IND tFlag;');
kod('');
kod(' mCurrentDate DATE;');
kod(' mHelper c%ROWTYPE;');
kod(' i BINARY_INTEGER;');
kod(' j BINARY_INTEGER;');
kod(' k BINARY_INTEGER;');
kod(' N BINARY_INTEGER;');
kod(' mTotalNewCount BINARY_INTEGER;');
kod(' mTotalOvwCount BINARY_INTEGER;');
kod(' mTotalVerCount BINARY_INTEGER;');
kod('BEGIN');
kod(' mCurrentDate := SYSDATE;');
kod(' mTotalNewCount := 0;');
kod(' mTotalVerCount := 0;');
kod(' mTotalOvwCount := 0;');
kod(' OPEN c;');
kod(' LOOP');
kod(' FETCH c BULK COLLECT INTO');
formatuj_liste2(mAll,'tr{COL},','',150,1,'','',' ');
kod(' trOPER_IND LIMIT 30000;');
kod('');
kod(' N := tr' || mAll(1) || '.COUNT;');
kod(' EXIT WHEN N=0;');
kod(' i:=1; k:=1; j:=1;');
kod('');
kod(' WHILE k<=N');
kod(' LOOP');
kod('');
kod(' WHILE i<=N AND trOPER_IND(i)=''I''');
kod(' LOOP');
kod(' i := i+1;');
kod(' END LOOP;');
kod(' IF j < i THEN j:=i; END IF;');
kod(' WHILE j<=N AND trOPER_IND(j)=''V''');
kod(' LOOP');
kod(' j := j+1;');
kod(' END LOOP;');
kod(' IF k<j THEN k:=j; END IF;');
kod('');
kod(' IF k<=N AND trOPER_IND(k)=''I'' THEN');
formatuj_liste2(mAll,'mHelper.{COL} := tr{COL}(i);','',150,1,'','','
');
kod(' mHelper.OPER_IND := trOPER_IND(i);');
kod('');
formatuj_liste2(mAll,'tr{COL}(i) := tr{COL}(k);','',150,1,'','',' ');
kod(' trOPER_IND(i) := trOPER_IND(k);');
kod('');
formatuj_liste2(mAll,'tr{COL}(k) := mHelper.{COL};','',150,1,'','','
');
kod(' trOPER_IND(k) := mHelper.OPER_IND;');
kod(' i:=i+1;');
kod(' END IF;');
kod('');
kod(' IF k<=N AND trOPER_IND(k)=''V'' THEN');
formatuj_liste2(mAll,'mHelper.{COL} := tr{COL}(j);','',150,1,'','','
');
kod(' mHelper.OPER_IND := trOPER_IND(j);');
kod('');
formatuj_liste2(mAll,'tr{COL}(j) := tr{COL}(k);','',150,1,'','',' ');
kod(' trOPER_IND(j) := trOPER_IND(k);');
kod('');
formatuj_liste2(mAll,'tr{COL}(k) := mHelper.{COL};','',150,1,'','','
');
kod(' trOPER_IND(k) := mHelper.OPER_IND;');
kod(' j:=j+1;');
kod(' END IF;');
kod('');
kod(' IF k<=N AND trOPER_IND(k)=''U'' THEN');
kod(' k:=k+1;');
kod(' END IF;');
kod(' END LOOP;');
kod(' mTotalNewCount := mTotalNewCount + i - 1;');
kod(' mTotalVerCount := mTotalVerCount + j - i;');
kod(' mTotalOvwCount := mTotalOvwCount + N - j + 1;');
kod('');
kod('');
kod(' IF i<=N THEN');
kod(' FORALL q IN i..j-1');
kod(' UPDATE ' || pTrgTable);
kod(' SET ' || pEndTS || ' = mCurrentDate, ' || pCurrRecFlag || '=0')
;
kod(' WHERE ' || pCurrRecFlag || '=1 AND');
formatuj_liste2(mNK,'{COL}=tr{COL}(q)',' AND ',150,1,'',';',' '
);
kod(' END IF;');
kod('');
kod(' IF j<=N THEN');
kod(' FORALL q IN j..N');
kod(' UPDATE ' || pTrgTable);
formatuj_liste2(mOvw,'{COL}=tr{COL}(q)',',',150,1,'SET ','',' '
);
kod(' WHERE ' || pCurrRecFlag || '=1 AND');
formatuj_liste2(mNK,'{COL}=tr{COL}(q)',' AND ',150,1,'',';',' '
);
kod(' END IF;');
kod('');
kod(' FORALL q IN 1..j-1');
kod(' INSERT INTO ' || pTrgTable);
formatuj_liste2(mAll,'{COL}',',',150,10,'(',',',' ');
kod(' ' || pSurrogateKey || ', ' || pStartTS ||', '|| pEndTS || ', '
|| pCurrRecFlag || ') VALUES (');
formatuj_liste2(mAll,'tr{COL}(q)',',',150,10,'',',',' ');
kod(' ' || pSequence || '.nextval,mCurrentDate,date''2999-12-31'',1);
');
kod('');
kod(' tr' || mAll(1) || '.DELETE;');
kod(' END LOOP;');
kod(' CLOSE c;');
kod(' COMMIT;');
kod(' :TOTAL_NEW_COUNT := mTotalNewCount;');
kod(' :TOTAL_VER_COUNT := mTotalVerCount;');
kod(' :TOTAL_OVW_COUNT := mTotalOvwCount;');
kod('END;');
execute_code;
END;
/

You might also like