1

我们有几个按天间隔分区的表。在执行清除作业以删除一天的分区时,我们的 DBA 通知我们,在执行清除之前,我们必须将所有外键删除到任何表中。这似乎是一个不必要的步骤,因此,我转向了 stackoverflow 的智慧。

 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,我们是否必须在清除之前删除/禁用外键约束,然后再创建它?是否存在必须发生这种情况的数据情况(可能不像我上面的示例所示)。

4

3 回答 3

2

似乎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;
于 2013-10-24T22:11:01.177 回答
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

检查约束类型...希望这会有所帮助。

于 2013-10-25T14:08:54.957 回答
1

不是一个直接的答案,但听起来你真正想要的是参考分区,它会:

  • 级联分区维护操作
  • 允许更简单的查询
  • 提供两个表的分区逻辑关联的元数据
  • 可能会在插入子表时增加一点开销。

http://docs.oracle.com/cd/B28359_01/server.111/b32024/partition.htm#CACIHDII

于 2013-12-12T08:29:02.270 回答