Predpokladám, že čitateľ tohto príspevku vie, čo je to duplicita záznamov, ak nie, jednoduché vysvetlenie pre duplicitu: znamená, že sa pokúšame vložiť do "cieľovej" tabuľky rovnaký záznam, ktorý má splnenú podmienku z kľúčov (buď primárneho alebo akéhokoľvek "UNIQUE" - jedinečného kľúča definovaného na "cieľovej" tabuľke). Pretože, ak by sme sa pokúsili vložiť do akejkoľvek tabuľky záznam, ktorého dáta sa zhodujú s hodnotami v spomenutých kľúčoch, databázový systém nám odmietne takýto záznam do tabuľky vložiť.
Ďalej predpokladám, že programátor ovláda základy SQL a PL SQL v prostredí Oracle 11g.
Vytvoríme si príklad.
Úloha: Potrebujeme prekopírovať dnešné záznamy zo "zdrojovej" tabuľky do "cieľovej", s kontrolou na duplicitu na primárny kľúč.
TABLE_SOURCE - "zdrojová" tabuľka z ktorej sa záznamy kopírujú.
TABLE_DEST - "cieľová" tabuľka do ktorej sa záznamy kopírujú zo "zdrojovej" tabuľky.
Stľpec ID_LOG - je primárnym kľučom v obidvoch tabuľkách.
Trocha si príklad zjednodušíme a máme tabuľky s úplne zhodnou štruktúrou.
Jednoduchý príklad, ako by na prvý pokus programátor chcel kód vytvoriť napr. pomocou anonymného PL SQL bloku:
DECLARE ID_LOG_VAR TABLE_SOURCE.ID_LOG%TYPE; BEGIN FOR REC IN (SELECT TS.ID_LOG, TS.NAME_DESC, TS.DATE_TIME FROM TABLE_SOURCE TS WHERE TS.DATE_TIME>TRUNC(SYSDATE)) /* napríklad takto: */ BEGIN SELECT TD.ID_LOG INTO ID_LOG_VAR FROM TABLE_DEST TD WHERE TD.ID_LOG=REC.ID_LOG; EXCEPTION WHEN NO_DATA_FOUND THEN ID_LOG_VAR := 0; END; IF ID_LOG_VAR = 0 THEN INSERT INTO TABLE_DEST (ID_LOG, NAME_DESC, DATE_TIME) VALUES (REC.ID_LOG, REC.NAME_DESC, REC.DATE_TIME); END IF; /* alebo napríklad takto: BEGIN INSERT INTO TABLE_DEST (ID_LOG, NAME_DESC, DATE_TIME) VALUES (REC.ID_LOG, REC.NAME_DESC, REC.DATE_TIME); EXCEPTION WHEN DUP_VAL_ON_INDEX THEN CONTINUE; END; */ END LOOP; COMMIT; EXCEPTION WHWN OTHERS THEN ROLLBACK; END;
Teraz si ukžážeme, ako to môžeme celé zjednodušiť.
V tomto prípade ale vytvoríme jednoduchý SQL kód, ktorý nám urobí toto všetko naraz jedným príkazom.
INSERT /*+ ignore_row_on_dupkey_index(TABLE_DEST, PK_TABLE_DEST) */ INTO TABLE_DEST (ID_LOG,NAME_DESC,DATE_TIME) SELECT TS.ID_LOG, TS.NAME_DESC, TS.DATE_TIME FROM TABLE_SOURCE TS WHERE TS.DATE_TIME>TRUNC(SYSDATE); COMMIT;
Hotovo.
Vysvetlenie:
Na celé toto sme zneužili SQL hint "ignore_row_on_dupkey_index".
PK_TABLE_DEST - je názov primárneho indexu (ako objektu) v "namespace" schéme, v ktorej sa tabuľka nachádza.
Týmto hintom sme jednoducho povedali databázovému serveru, že záznamy, ktoré sú duplicitné na hodnotu primárneho kľúča, nemá do "cieľovej" tabuľky vložiť a má ich jednoducho ignorovať. Tento hint funguje aj pre iné indexy, samozrejme aj na nie "UNIQUE" indexy, vtedy ale musíme rátať s tým, že ak hint síce zachytí duplicitu na hodnoty v zadanom indexe, ale potom pre hodnoty v primárnom kľúči alebo iných UNIQUE kľúčoch (ak sú na tabuľke vytvorené) duplicitu nezachytí a SQL príkaz jednoducho zlyhá. Čiže treba mať na pamäti tento fakt.
S pozdravom a prajem veľa kódu bez chýb:)