问题描述
Hi Chirs/Connor, I have written below procedure to move records from tables (from Primary DB to Arcihval DB). The logic is to merge records on Archival DB then DELETE those rows from Primary as well. We have already have same table structre in Archival like in Primary DB. This procedure gets called in a loop where around 30-40 table names (e.g. tb_orders, tb_order_history, so on..) This works perfectly fine when there are not foreign key constraints. But am not able build a logic where i can handle parent child records movement as well as delete. Scenario is Parent:Child:Sub Child - -- TB_ORDERS -- TB_ORDER_DETAILS -- TB_ORDERS_HISTORY Can you suggest how to handle such scenarios, PLEASE!! PROCEDURE p_dynamic_merge(piv_table_name IN VARCHAR2, -- Table name which need to archive pin_max_process IN NUMBER, -- Degree of PARALLEL Operation e.g. 8 pin_max_merge IN NUMBER, -- BULK COLLECT LIMIT e.g. 5000 piv_where_clause IN VARCHAR2, -- where condition for a table to fetch specific rows n merge over DB link.. pon_total_rec OUT NUMBER, -- No. of rows merged. pov_retval OUT VARCHAR2, pov_errmsg OUT VARCHAR2) IS -- Variable declaration -- v_insert_src VARCHAR2(20000); v_insert_tgt VARCHAR2(20000); v_update_src VARCHAR2(20000); v_condition_src VARCHAR2(20000); v_temp_src VARCHAR2(1000); v_temp_tgt VARCHAR2(1000); v_final_query VARCHAR2(20000); n_cnt PLS_INTEGER; v_from VARCHAR2(100); v_to VARCHAR2(100); v_str_cur VARCHAR2(10000); n_row_updated NUMBER(10); d_date DATE; TYPE r_cursor IS REF CURSOR; c_cur_var r_cursor; TYPE t_rowid IS TABLE OF ROWID; -- index by binary_integer; tb_rowid t_rowid := t_rowid(); err_archive_data EXCEPTION; BEGIN v_insert_src := NULL; v_insert_tgt := NULL; v_update_src := NULL; v_condition_src := NULL; v_temp_src := NULL; v_temp_tgt := NULL; n_cnt := 0; -- Get source table columns -- SELECT LISTAGG(' src.' || column_name, ', ') WITHIN GROUP (ORDER BY column_id) INTO v_insert_src FROM user_tab_columns WHERE table_name = UPPER(piv_table_name); v_insert_tgt := REPLACE(v_insert_src, 'src.', 'tgt.'); -- Get Non-key columns -- SELECT LISTAGG(' tgt.' || tab.column_name || ' = ' || ' src.' || tab.column_name, ', ') WITHIN GROUP (ORDER BY tab.column_name) INTO v_update_src FROM (SELECT column_name FROM user_tab_columns WHERE table_name = UPPER(piv_table_name) MINUS SELECT column_name FROM user_constraints a, user_cons_columns b WHERE a.constraint_name = b.constraint_name AND a.constraint_type = 'P' AND a.table_name = UPPER(piv_table_name)) tab; -- Get primary key columns -- SELECT LISTAGG(' src.'||column_name || ' = '|| ' tgt.'||column_name, ' AND ') WITHIN GROUP (ORDER BY column_name) INTO v_condition_src FROM user_constraints a , user_cons_columns b WHERE a.constraint_name = b.constraint_name AND a.constraint_type = 'P' AND a.table_name = UPPER(piv_table_name); n_row_updated := 0; v_str_cur := 'SELECT ROWID FROM ' || piv_table_name || ' WHERE '|| piv_where_clause; OPEN c_cur_var FOR v_str_cur; LOOP FETCH c_cur_var BULK COLLECT INTO tb_rowid LIMIT pin_max_merge; EXIT WHEN tb_rowid.COUNT = 0; -- Use of object types i.e. tb_rowid not allowed for DB link operation.. -- Load GTT which will hold ROWIDs which can be used in MERGE statement.. DBMS_OUTPUT.PUT_LINE('B4 GTT :'||TO_CHAR(SYSDATE,'DD/MM/YYYY HH24:MI:SS')); FORALL i IN tb_rowid.FIRST .. tb_rowid.LAST INSERT /*+ PARALLEL(tb_archive_staging, 2) */ INTO tb_archive_staging VALUES (tb_rowid(i)); DBMS_OUTPUT.PUT_LINE('After GTT :'||TO_CHAR(SYSDATE,'DD/MM/YYYY HH24:MI:SS')); v_final_query := 'MERGE /*+ PARALLEL('||piv_table_name||', '||pin_max_process||') */ INTO '|| piv_table_name ||'@'||pkv_archive_db_link||' tgt USING ( SELECT /*+ PARALLEL('||piv_table_name||', '||pin_max_process||') */ * FROM ' || piv_table_name || ' WHERE ROWID IN (SELECT row_id FROM tb_archive_staging)) src ON ('|| v_condition_src ||') WHEN MATCHED THEN UPDATE SET '|| v_update_src ||' WHEN NOT MATCHED THEN INSERT (' || v_insert_tgt || ') VALUES (' || v_insert_src ||')'; -- Enable DML Parallelism -- BEGIN EXECUTE IMMEDIATE 'ALTER SESSION ENABLE PARALLEL DML' ; EXCEPTION WHEN OTHERS THEN NULL; END; DBMS_OUTPUT.PUT_LINE('B4 DB Link :'||TO_CHAR(SYSDATE,'DD/MM/YYYY HH24:MI:SS')); EXECUTE IMMEDIATE v_final_query; DBMS_OUTPUT.PUT_LINE('After DB Link :'||TO_CHAR(SYSDATE,'DD/MM/YYYY HH24:MI:SS')); n_row_updated := n_row_updated + SQL%ROWCOUNT; COMMIT; v_final_query := 'BEGIN FORALL i IN :tb_rowid.FIRST .. :tb_rowid.LAST DELETE FROM '||piv_table_name||' WHERE rowid = :tb_rowid(i); COMMIT; END;'; EXECUTE IMMEDIATE v_final_query USING tb_rowid, tb_rowid, tb_rowid; tb_rowid.DELETE; END LOOP; CLOSE c_cur_var; pon_total_rec := n_row_updated; EXCEPTION WHEN OTHERS THEN ROLLBACK; pov_retval := SQLCODE; pov_errmsg := SQLERRM||'#'||dbms_utility.format_error_backtrace; END p_dynamic_merge;复制
专家解答
您正在发现以安全一致的方式处理数据复制的艰巨任务 (这就是为什么我们有Streams和Goldengate)。
如果你坚持这条路,你需要考虑
a) 使用延迟约束,或
b) 在数据加载期间禁用约束,然后重新启用它们。
但是构建自己的复制系统并不是微不足道的。非常不平凡
如果你坚持这条路,你需要考虑
a) 使用延迟约束,或
b) 在数据加载期间禁用约束,然后重新启用它们。
但是构建自己的复制系统并不是微不足道的。非常不平凡
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。