2013-10-24 43 views
1

我們有幾個按天間隔分區的表。在執行清除作業以減少一天的分區時,我們的DBA已通知我們,在執行清除之前,我們將不得不將所有外鍵刪除到任何表。這似乎是一個不必要的步驟,因此,我正轉向使用stackoverflow的智慧。Oracle在清除間隔分區表期間強制刪除外鍵

parentTable  childTable 
ID (PK)  ID (PK)(FK) 
date (PK)  date (PK)(FK) 
       otherKey(PK) 

parentTable    childTable 
ID  date   ID date otherKey 
1  10/23  1  10/23  a 
2  10/23  2  10/23  a 
3  10/23  3  10/23  a 
1  10/24  1  10/24  a 
2  10/24  2  10/24  a 
         2  10/24  b 

的問題是,如果我們放棄從childTable(第一)的10/23分區,然後parentTable,將我們不得不放棄/清洗前禁用外鍵約束,事後重新創建?有沒有數據的情況下,這將不得不發生(可能不像上面我的例子中所示)。

+0

什麼原因做了DBA給你? –

+0

即使按照正確的順序刪除,數據庫也能夠發現主鍵存在,並且不會處理父表,除非除去引用父表的所有FK。這並不是說它會根據記錄的值導致違規行爲。在分區表中刪除分區時,Oracle會查看是否存在正在使用的外鍵約束。如果是這樣,它不允許從父表中刪除分區(任何分區)。 – user2210179

回答

1

似乎DBA是正確的,測試的情況:

CREATE TABLE parent_tab (
    id NUMBER PRIMARY KEY, 
    start_date DATE 
) 
PARTITION BY RANGE (start_date) 
INTERVAL(NUMTODSINTERVAL(1, 'DAY')) 
( 
    PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('01-01-2013', 'DD-MM-YYYY')) 
); 

INSERT INTO parent_tab VALUES (1, DATE '2012-01-01'); 
INSERT INTO parent_tab VALUES (2, DATE '2013-01-02'); 
INSERT INTO parent_tab VALUES (3, DATE '2013-01-03'); 

CREATE TABLE child_tab (
    start_date DATE, 
    parent_tab_id NUMBER REFERENCES parent_tab(id) 
) 
PARTITION BY RANGE (start_date) 
INTERVAL(NUMTODSINTERVAL(1, 'DAY')) 
( 
    PARTITION pos_data_p2 VALUES LESS THAN (TO_DATE('01-01-2013', 'DD-MM-YYYY')) 
); 

INSERT INTO child_tab VALUES (DATE '2012-01-01', 1); 
INSERT INTO child_tab VALUES (DATE '2013-01-02', 2); 
INSERT INTO child_tab VALUES (DATE '2013-01-03', 3); 

COMMIT; 

SELECT table_name, partition_name FROM user_tab_partitions WHERE table_name IN ('PARENT_TAB', 'CHILD_TAB'); 

TABLE_NAME      PARTITION_NAME    
------------------------------ ------------------------------ 
CHILD_TAB      POS_DATA_P2      
CHILD_TAB      SYS_P69       
CHILD_TAB      SYS_P70       
PARENT_TAB      POS_DATA_P2      
PARENT_TAB      SYS_P67       
PARENT_TAB      SYS_P68       

ALTER TABLE child_tab DROP PARTITION SYS_P69; 

> table CHILD_TAB altered. 

ALTER TABLE parent_tab DROP PARTITION SYS_P67; 

ALTER TABLE parent_tab DROP PARTITION SYS_P67 
Error report: 
SQL Error: ORA-02266 - "unique/primary keys in table referenced by enabled foreign keys" 
*Cause: An attempt was made to truncate a table with unique or 
      primary keys referenced by foreign keys enabled in another table. 
      Other operations not allowed are dropping/truncating a partition of a 
      partitioned table or an ALTER TABLE EXCHANGE PARTITION. 
*Action: Before performing the above operations the table, disable the 
      foreign key constraints in other tables. You can see what 
      constraints are referencing a table by issuing the following 
      command: 
      SELECT * FROM USER_CONSTRAINTS WHERE TABLE_NAME = "tabnam"; 

編輯

正如作者所指出的那樣,禁用約束的工作原理:

SELECT table_name, constraint_name, constraint_type FROM user_constraints WHERE table_name = 'CHILD_TAB'; 

TABLE_NAME      CONSTRAINT_NAME    CONSTRAINT_TYPE 
------------------------------ ------------------------------ --------------- 
CHILD_TAB      SYS_C0033723     R    

ALTER TABLE child_tab DISABLE CONSTRAINT SYS_C0033723; 

ALTER TABLE parent_tab DROP PARTITION SYS_P67; 

> table PARENT_TAB altered. 

ALTER TABLE child_tab ENABLE CONSTRAINT SYS_C0033723; 
+0

感謝,但是從我正在閱讀的內容來看,「在執行上述操作表之前,禁用其他表中的外鍵約束」FK約束不必被刪除和創建,它們可以被禁用並且它應該可以工作。這很容易,因爲所有這些表都將處於相同的模式,禁用此所有者/模式中的所有FK,執行所有刪除分區,然後啓用它們。 – user2210179

+0

@ user2210179你是對的,我已經給我的答案添加了一個例子。 –

1
有一天我

將學會在那裏管理我的代碼,所以...

CREATE OR REPLACE PROCEDURE manage_constraints (i_status IN varchar2) 

IS 

    CURSOR ref_cons 

    IS 

     SELECT constraint_name, table_name, status 

     FROM user_constraints 

     WHERE constraint_type in ('R') ; -- YOu can disable more constraints type 


    v_status VARCHAR2 (10); 

    v_sql  VARCHAR2 (300); 

BEGIN 

    FOR e_cons IN ref_cons 

    LOOP 

     v_sql := 

      'ALTER TABLE ' 

     || e_cons.table_name 

     || ' ' 

     || i_status 

     || ' CONSTRAINT ' 

     || e_cons.constraint_name; 


     --DBMS_OUTPUT.put_line (v_sql); 

     EXECUTE IMMEDIATE v_sql; 

    END LOOP; 

EXCEPTION 

    WHEN OTHERS 

    THEN 

     RAISE; 

END; 


--exec manage_constraints('DISABLE'); 

--exec manage_constraints('ENABLE'); 

在那裏你可以只禁用所有的約束,然後啓用它們。

select * from user_constraints 

檢查約束類型...希望這會有所幫助。