如果在 Oracle 中删除附加有外键的主键约束,然后重新启用主键,会发生什么情况?

What happens when you drop a primary key constraint that has a foreign key attached to it in Oracle and then re-enable the primary key?

好吧,假设你有 2 个表,Table1Table2

Table1 的主键是 Table2 的外键。如果删除 Table1 上的主键约束,然后使用 Alter Table 命令重新启用它,Table2 上的外键是否也会自动重新启用?

让我们试试看会发生什么。

首先创建表 t1 和 t2。

CREATE TABLE t1 (parent_id NUMBER);
Table created
CREATE TABLE t2 (child_id NUMBER);
Table created

然后创建 2 个约束

ALTER TABLE t1 ADD CONSTRAINT t1_pk PRIMARY KEY (parent_id) USING INDEX;
Table altered
ALTER TABLE t2 ADD CONSTRAINT t2_fk FOREIGN KEY (child_id) REFERENCES t1;
Table altered

现在看字典和select2个表的约束条件

SELECT c.CONSTRAINT_NAME, c.CONSTRAINT_TYPE, c.R_CONSTRAINT_NAME
FROM User_Constraints c WHERE c.TABLE_NAME IN ('T1', 'T2');
CONSTRAINT_NAME                CONSTRAINT_TYPE R_CONSTRAINT_NAME
------------------------------ --------------- ------------------------------
T1_PK                          P               
T2_FK                          R               T1_PK

我们看到 1 个主键 (P) 和 1 个外键 (R) 然后放下 pk

ALTER TABLE t1 DROP CONSTRAINT t1_pk CASCADE;
Table altered

cascade 关键字指示 oracle 隐式删除引用要删除的 pk 的所有 fk 约束。没有级联你会得到 ORA-02273: 这个 unique/primary 键被一些外键引用 并且 pk 没有被删除。

再看看字典select2个表的约束条件

SELECT c.CONSTRAINT_NAME, c.CONSTRAINT_TYPE, c.R_CONSTRAINT_NAME
FROM User_Constraints c WHERE c.TABLE_NAME IN ('T1', 'T2');
CONSTRAINT_NAME                CONSTRAINT_TYPE R_CONSTRAINT_NAME
------------------------------ --------------- ------------------------------

没有行 - pk 和 fk 都没有了。重新创建 pk

ALTER TABLE t1 ADD CONSTRAINT t1_pk PRIMARY KEY (parent_id) USING INDEX;
Table altered

再看看字典

SELECT c.CONSTRAINT_NAME, c.CONSTRAINT_TYPE, c.R_CONSTRAINT_NAME
FROM User_Constraints c WHERE c.TABLE_NAME IN ('T1', 'T2');
CONSTRAINT_NAME                CONSTRAINT_TYPE R_CONSTRAINT_NAME
------------------------------ --------------- ------------------------------
T1_PK                          P               

只创建了pk。清理测试用例

DROP TABLE t2;
Table dropped
DROP TABLE t1;
Table dropped

让我们对您提出的问题进行测试。我希望我理解正确的前提:

  • 我有一个 table MY_PK,主键在列 C1
  • 我有一个 table MY_FK 包含 C1 列上的主键,它也是 table MY_PK.[=40 中 C1 列的外键=]
  • 您想禁用或删除 table MY_FK 中的主键以查看外键会发生什么情况。

来玩吧:

SQL> create table my_pk ( c1 number primary key , c2 number );

Table created.

SQL> create table my_fk ( c1 number primary key , c2 number, constraint my_fk_constraint foreign key (c1) references my_pk (c1) ) ;

Table created.

SQL>  select table_name, constraint_name, constraint_type, status from dba_constraints where table_name in ( 'MY_FK' , 'MY_PK' ) and owner = 'MYOWNER' ;

TABLE_NAME                     CONSTRAINT_NAME                C STATUS
------------------------------ ------------------------------ - --------
MY_PK                          SYS_C00141013                  P ENABLED
MY_FK                          SYS_C00141016                  P ENABLED
MY_FK                          MY_FK_CONSTRAINT               R ENABLED

所以,让我们按照您的要求进行操作:

禁用 table MY_FK 中的主键,它也是 Table 的外键 MY_PK

SQL> alter table my_fk disable primary key ;

Table altered.

SQL>  select table_name, constraint_name, constraint_type, status from dba_constraints where table_name in ( 'MY_FK' , 'MY_PK' ) and owner = 'MY_OWNER';

TABLE_NAME                     CONSTRAINT_NAME                C STATUS
------------------------------ ------------------------------ - --------
MY_PK                          SYS_C00141013                  P ENABLED
MY_FK                          SYS_C00141016                  P DISABLED
MY_FK                          MY_FK_CONSTRAINT               R ENABLED

让我们评估一下外键是否仍然强制执行,即使pk被禁用。您可以在上面看到 FK 在字典中显示为 ENABLED。

SQL> insert into my_pk values ( 1 , 1 );

1 row created.

SQL> commit;

Commit complete.

SQL> insert into my_fk values ( 2, 1 );
insert into my_fk values ( 2, 1 )
*
ERROR at line 1:
ORA-02291: integrity constraint (MYOWNER.MY_FK_CONSTRAINT) violated - parent
key not found

尽管 PK 已禁用,但仍强制执行外键,如果需要,您仍然可以插入重复项

SQL> insert into my_fk values ( 1 , 1 );

1 row created.

SQL> rollback;

Rollback complete.

SQL>

我们重新启用 table MY_FK

中的 PK
SQL> alter table my_fk enable primary key ;

Table altered.

SQL>  select table_name, constraint_name, constraint_type, status from dba_constraints where table_name in ( 'MY_FK' , 'MY_PK' ) ;

TABLE_NAME                     CONSTRAINT_NAME                C STATUS
------------------------------ ------------------------------ - --------
MY_PK                          SYS_C00141013                  P ENABLED
MY_FK                          SYS_C00141016                  P ENABLED
MY_FK                          MY_FK_CONSTRAINT               R ENABLED

将主键放入 table MY_FK 这也是 MY_PK

的外键
SQL> alter table my_fk drop primary key ;

Table altered.

SQL> select table_name, constraint_name, constraint_type, status from dba_constraints 
where table_name in ( 'MY_FK' , 'MY_PK' ) ;

TABLE_NAME                     CONSTRAINT_NAME                C STATUS
------------------------------ ------------------------------ - --------
MY_PK                          SYS_C00141013                  P ENABLED
MY_FK                          MY_FK_CONSTRAINT               R ENABLED

SQL> insert into my_pk values ( 2 , 2 );

1 row created.

SQL> select * from my_pk ;

        C1         C2
---------- ----------
         1          1
         2          2

SQL> insert into my_fk values ( 2 ,2 );

1 row created.

SQL> select * from my_fk ;

        C1         C2
---------- ----------
         1          1
         2          2

SQL> insert into my_fk values ( 3 , 3 );
insert into my_fk values ( 3 , 3 )
*
ERROR at line 1:
ORA-02291: integrity constraint (MYOWNER.MY_FK_CONSTRAINT) violated - parent
key not found

因此,无论是禁用主键约束还是在 table MY_FK 中删除,外键仍然是强制执行的。显然,您可以在禁用主键的同时向 table 添加重复项。我没有在我的测试用例中使用选项 CASCADE,这改变了另一个答案中提供的场景。