外键是否总是引用另一张表中的唯一键?

26

在子表中,外键(单一列)引用的父键是否可能存在一些重复值?

3个回答

29
根据 SQL 标准,外键必须引用父表的主键或唯一键。如果主键有多列,则外键必须具有相同数量和顺序的列。因此外键引用父表中的唯一行,不会有重复项。
关于您的评论:
如果 T.A 是主键,则不能有任何重复项。任何主键必须是唯一且非空的。因此,如果子表具有引用父表主键的外键,则必须匹配非空唯一值,因此精确引用父表中的一行。在这种情况下,您无法创建引用多个父行的子行。
您可以创建一个外键列为空的子行,这样它就不会引用父表中的任何行。

谢谢,但是如果我们谈论单列外键如:列'a'是子表t中引用父表T中列'A'的外键,那么现在在任何情况下列A可能都不会在表T中有任何重复值吗?这是否意味着外键必须始终引用另一个表中的主键? - ratsy
2
@ratsy:外键必须始终引用声明为PRIMARY KEY或UNIQUE的列。 (除非您使用MySQL。但即使在MySQL中,您仍应仅针对PRIMARY KEY或UNIQUE列。请搜索http://dev.mysql.com/doc/refman/5.6/en/innodb-foreign-key-constraints.html以获取“系统不强制执行所需的引用列是唯一的”) - Mike Sherrill 'Cat Recall'
@Catcall:没错,但是@ratsy将这个问题标记为“oracle”,所以我没有提到InnoDB的非标准行为。即使使用InnoDB,我强烈建议不要引用非唯一的父行,因为那样很容易混淆。 - Bill Karwin
非常感谢你的解答,Bill和Catcall。我问这个问题是因为我们的组织正在汇总一些数据库,在其中一个数据库中,我发现外键引用了一个父键,而该父表中有两三个重复记录,但该父键在此处未定义为主键 :(....所以是的,Catcall理解了我的问题,这里提到的数据库是Oracle数据库。再次感谢Bill,那么应该如何纠正这个问题呢? - ratsy

7
不,这是不可能的。
当你在表上定义外键约束时,意味着在关联表上只有一个对应的键。如果在关联表上存在多个键,那么哪个才是所指的呢?
维基百科在“ 外键”词条中给出了这个定义:
外键是关系表中匹配另一张表的候选键的字段。
候选键在表内是唯一的。

7

是的,外键可以引用具有重复值的列。

如果主键使用非唯一索引并且在创建时未进行验证,则可能会发生这种情况。(但我从未在现实生活中见过这样的情况。如@Bill Karwin所指出的那样,这将非常令人困惑。因此,这可能不是您真正需要担心的情况。)

--Create a table with two duplicate rows
create table test1(a number);
insert into test1 values(1);
insert into test1 values(1);
commit;

--Create a non-unique index
create index test1_index on test1(a);

--Use the non-unique index for the primary key, do not validate
alter table test1 add constraint test1_pk primary key (a)
    using index test1_index novalidate;

--Build another table with a foreign key to TABLE1
create table test2(a number,
    constraint test2_fk foreign key (a) references test1(a));

--Inserting a value that refers to the duplicate value still works.
insert into test2 values(1);
commit;

--The foreign key still works:
--ORA-02291: integrity constraint (TEST2_FK) violated - parent key not found
insert into test2 values(2);

--The primary key works as expected, but only for new values:
--ORA-00001: unique constraint (TEST1_PK) violated
insert into test1 values(1);

有点古怪。我认为这属于“你为什么要这样做?”的范畴 :-) 但感谢您提供清晰的示例! - Bill Karwin
感谢Jonearles提供的示例!...我正在使用的数据库中出现了相同的情况,但为什么和如何解决呢..? - ratsy
使用非唯一索引作为主键有几个好处:可延迟的约束、更多重建选项(特别是并行性)、索引在约束之前存在等。请参阅此处以获取有关唯一索引与非唯一索引的信息:http://richardfoote.wordpress.com/2008/06/04/primary-keys-and-non-unique-indexes-whats-really-happening/NOVALIDATE 有点奇怪。据我所知,除非您只需要一些“坏”数据,否则没有使用它的优势。这些情况确实应该有记录。如果没有记录,也许只是一个错误? - Jon Heller
好的,谢谢Jonearles为我澄清这个问题。我所说的数据库没有关于这些重复记录的文档,这是一个错误的数据库。如果需要帮助,我会回来的。不过还是非常感谢你的解释。 - ratsy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接