提问人:Eshe 提问时间:11/17/2023 最后编辑:marc_sEshe 更新时间:11/17/2023 访问量:33
更改 Oracle 主键
Altering Oracle Primary Keys
问:
Oracle 表可以有一个或多个列被指定为主键。此指定在创建表时发生。假设该表的主键中有多个列,其中一些列是外键。
- 我们可以更改表的主键并使某些外键为 null (即将它们从 not null 更改为 null)吗?
- 是否建议在创建后更改 oracle 表的主键?
这是一个理论问题。我正在努力获得专业人士的建议和经验。
答:
您可以更改属于主键的列,并将标记为 (able),但由于您定义了主键 (P) 约束,因此如果插入值,它们仍将被拒绝。主键不允许在其列中包含值:NULL
NULL
NULL
create table tmp1 (col1 integer not null, col2 integer not null, constraint pk_tmp1 unique (col1));
create table tmp2 (col1 integer not null, col2 integer not null, constraint pk_tmp2 primary key (col1), constraint fk_col1 foreign key (col1) references tmp1(col1));
alter table tmp2 modify (col1 null); -- this succeeds
insert into tmp1 values (1,100);
insert into tmp2 values (null,200); -- this however still fails
但是,您可以删除主键约束,并在其位置创建唯一 (U) 约束。唯一键允许作为允许的值:NULL
alter table tmp2 drop constraint pk_tmp2;
alter table tmp2 add constraint uk_tmp2 unique (col1);
insert into tmp2 values (null,200); -- this now works
但是,请考虑一些特殊行为:
如果某个值位于唯一约束的唯一列中,则不会强制执行该值。您可以根据需要插入任意数量的行,它允许您。但是,如果唯一约束是多列约束,则其中一列将充当离散值,并且只允许一个(其他列相同):NULL
(null,200)
NULL
NULL
--Unique key on col1 only:
insert into tmp2 values (null,200); -- this works!
insert into tmp2 values (null,200); -- this works!
insert into tmp2 values (null,200); -- this works!
--Unique key on col1,col2:
delete from tmp2;
alter table tmp2 drop constraint uk_tmp2;
alter table tmp2 add constraint uk_tmp2 unique (col1,col2);
insert into tmp2 values (null,200); -- this works
insert into tmp2 values (null,200); -- this fails
(这实际上是相当不错的行为。例如,可以在 2 类历史记录表上利用这一点,在该表中,您可以使用开始/结束日期对行进行版本控制,并使用 NULL 作为当前行的结束日期,而不是像 12/31/9999 这样的虚拟值。多列唯一约束可以强制每个实体只有一个当前行(NULL 结束日期)。
此外,FK 约束的任何列中的 a 都会导致 FK 约束不执行任何操作。您可以在子表中插入 a,即使父表中没有对应的表:NULL
NULL
NULL
drop table tmp2;
drop table tmp1;
create table tmp1 (col1 integer null, col2 integer null, constraint pk_tmp1 unique (col1,col2));
create table tmp2 (col1 integer null, col2 integer null, constraint pk_tmp2 unique (col1,col2), constraint fk_col12 foreign key (col1,col2) references tmp1(col1,col2));
insert into tmp1 values (null,100);
insert into tmp2 values (null,100); -- this works
insert into tmp2 values (null,200); -- but so does this! even though there is no 200 in the parent
所以是的,你可以通过用唯一键替换主键来制作其中一些列,但你必须注意在约束列中导致的奇怪行为。NULL
NULL
不能将主键设置为可为 null。但是外键可以为空。
原因是:主键标识表示关系中实体的记录。 意味着未知,或者换句话说,无法识别。您不能拥有部分或完全未知的标识符,因为这违背了拥有标识符(即主键)的目的。null
但是,外键是基于具有外键的记录与外键引用其主键的记录之间的关系对另一个实体的引用。
例如,person 表可能有一个 workplace_id 的外键,它表示他/她工作的工作场所的 ID,但有些人没有这样的 id,因为他们失业了,或者他们的工作场所未知。
因此,您可以在 person 表中创建 workplace_id为 null 的记录。
因此,如果您的第一个问题指的是您拥有可为 null 的外键的情况,那么答案是肯定的。
关于第二个问题,答案通常是否定的,因为主键是记录的主要标识符,并且可能有对它的引用。然而,有时你被迫这样做,然后这不是建议的问题。当你可以在缺乏参考资料的情况下做到这一点时,即使这样,你也应该在这样做之前三思而后行。
评论