首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

Oracle 約束與觸發器批量啟用/停用存儲過程:資料遷移合併的利器

     編輯:Oracle 資料庫相關知識

業務場景:跨庫合併與代碼表整理

銀行從市級集中升級為省級/國家級資料集中,DBA 核心任務是將分散資料庫合併、統一代碼表。合併前必須**停用所有外鍵與觸發器**避免約束衝突,資料整理完成後再**批量啟用**。本文提供生產級存儲過程 P_ALTERCONS 實現一鍵操作。

存儲過程規格

SQL> SET SERVEROUTPUT ON;
SQL> ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS';
SQL> EXEC P_ALTERCONS('ENABLE');  -- 或 'DISABLE'
  • 參數僅接受 ENABLE / DISABLE,大小寫不敏感
  • 處理當前 Schema 下所有 CONSTRAINT_TYPE='R'(外鍵)與所有觸發器
  • 不處理 PK/UK,建議勿隨意停用主鍵/唯一約束
  • 輸出詳細日誌:開始/結束時間、處理筆數、錯誤明細

核心邏輯解析

CREATE OR REPLACE PROCEDURE P_ALTERCONS(AS_ALTER VARCHAR2) AS
    v_CursorID INTEGER;
    v_StrCon   VARCHAR2(300);
    v_FkNum    NUMBER := 0;
    v_TriNum   NUMBER := 0;
    CURSOR C_CON IS SELECT * FROM USER_CONSTRAINTS WHERE CONSTRAINT_TYPE='R';
    CURSOR C_TRIGGER IS SELECT TRIGGER_NAME, STATUS FROM USER_TRIGGERS;
BEGIN
    DBMS_OUTPUT.PUT_LINE('BEGIN TIME: '||TO_CHAR(SYSDATE));
    
    IF UPPER(AS_ALTER) NOT IN ('ENABLE','DISABLE') THEN
        DBMS_OUTPUT.PUT_LINE('ERROR: 參數必須為 ENABLE 或 DISABLE!');
        RETURN;
    END IF;

    -- 處理外鍵
    v_CursorID := DBMS_SQL.OPEN_CURSOR;
    FOR R_CON IN C_CON LOOP
        IF (UPPER(AS_ALTER)='DISABLE' AND R_CON.STATUS='ENABLED') OR
           (UPPER(AS_ALTER)='ENABLE'  AND R_CON.STATUS='DISABLED') THEN
            v_StrCon := 'ALTER TABLE '||R_CON.OWNER||'.'||R_CON.TABLE_NAME||
                        ' '||UPPER(AS_ALTER)||' CONSTRAINT '||R_CON.CONSTRAINT_NAME;
            BEGIN
                DBMS_SQL.PARSE(v_CursorID, v_StrCon, DBMS_SQL.NATIVE);
                v_FkNum := v_FkNum + 1;
            EXCEPTION
                WHEN OTHERS THEN
                    IF SQLCODE = -2298 THEN  -- 父鍵不存在等
                        P_CON_ERR(R_CON.CONSTRAINT_NAME);  -- 自訂錯誤處理
                    END IF;
                    DBMS_OUTPUT.PUT_LINE('ERROR: '||SQLERRM);
            END;
        END IF;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('====== Foreign Keys were '||AS_ALTER||', total '||v_FkNum||' ======');

    -- 處理觸發器
    FOR T_TRIGGER IN C_TRIGGER LOOP
        IF (UPPER(AS_ALTER)='DISABLE' AND T_TRIGGER.STATUS='ENABLED') OR
           (UPPER(AS_ALTER)='ENABLE'  AND T_TRIGGER.STATUS='DISABLED') THEN
            v_StrCon := 'ALTER TRIGGER '||T_TRIGGER.TRIGGER_NAME||' '||UPPER(AS_ALTER);
            BEGIN
                DBMS_SQL.PARSE(v_CursorID, v_StrCon, DBMS_SQL.NATIVE);
                v_TriNum := v_TriNum + 1;
            EXCEPTION
                WHEN OTHERS THEN
                    DBMS_OUTPUT.PUT_LINE('ERROR: '||SQLCODE||' '||SQLERRM);
            END;
        END IF;
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('====== Triggers were '||AS_ALTER||', total '||v_TriNum||' ======');
    
    DBMS_SQL.CLOSE_CURSOR(v_CursorID);
    DBMS_OUTPUT.PUT_LINE('END TIME: '||TO_CHAR(SYSDATE));
END;
/

關鍵設計亮點

  • 冪等性:僅處理狀態需變更的物件,重複執行無副作用
  • 動態 SQL:使用 DBMS_SQL 解析執行 DDL,支援運行時建構指令
  • 錯誤隔離:單一物件失敗不中斷整體流程,記錄錯誤碼 -2298 等關鍵異常
  • 審計追蹤:完整輸出時間戳、處理統計,滿足變更管理審計需求

擴展建議

  1. 新增參數控制是否處理 PK/UK/CHECK 約束
  2. 支援指定表名清單/排除清單
  3. 整合 DBMS_METADATA 產生完整 DDL 備份供回滾
  4. 包裝為排程 Job 自動化執行

這個存儲過程是大型資料遷移、合併、代碼表重構專案的標準配備,將原本需要數十條手工指令的高風險操作封裝為單一可審計、可重試、可監控的安全呼叫。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved