如果在 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 个表,Table1
和 Table2
。
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,这改变了另一个答案中提供的场景。
好吧,假设你有 2 个表,Table1
和 Table2
。
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
中的 PKSQL> 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,这改变了另一个答案中提供的场景。