外键可以引用一个非唯一索引吗?

我以为一个外键意味着一行必须引用一行,但我正在查看一些表,这是绝对不是这样的情况。 Table1的column1在table2中的column2上有一个外键约束,但是在table2中有很多logging在column2中有相同的值。 第2列还有非唯一索引。 这是什么意思? 外键约束是否仅仅意味着至less有一条logging必须存在右列中的正确值? 我认为这意味着必须有一个这样的logging(不知道这个图像是否有空值,但我现在不那么在意)。

更新:显然,这种行为是特定于MySQL,这是我正在使用,但我没有提到它在我原来的问题。

从MySQL文档 :

InnoDB允许外键约束引用非唯一键。 这是对标准SQL的InnoDB扩展。

但是,有一个实际的原因是为了避免引用表的非唯一列上的外键。 也就是说,在这种情况下,“ON DELETE CASCADE”的语义应该是什么?

文件进一步build议 :

对包含NULL值的非唯一键或键的外键引用的处理没有定义好(…)build议使用仅引用UNIQUE(包括PRIMARY)和NOT NULL键的外键。

你的分析是正确的。 这些键不必是唯一的,并且约束将作用于匹配行的集合。 通常不是一个有用的行为,但情况可能出现在你想要的地方。

是的,你可以创build任何表中的任何列的外键。 不过,大多数情况下,您都会将它们创build为主键。

如果确实使用不指向主键的外键,则可能还需要为了提高性能而为所引用的列创build(非唯一)索引。

取决于你正在使用的RDBMS。 我认为有些人会隐含地这样做,或者使用其他一些技巧。 RTM。

发生这种情况时,通常意味着两个外键正在彼此链接。 通常情况下,包含密钥作为主键的表甚至不在模式中。

示例:两个表,COLLEGES和STUDENTS,都包含一个名为ZIPCODE的列。

如果我们做一个快速检查

SELECT * FROM COLLEGES JOIN STUDENTS ON COLLEGES.ZIPCODE = STUDENTS.ZIPCODE 

我们可能会发现这种关系是多对多的。 如果我们的模式有一个名为ZIPCODES的表格,使用主键ZIPCODE,这将是显而易见的事情。

但是我们的模式没有这样的表格。 仅仅因为我们的模式没有这样的表格并不意味着这样的数据不存在,但是。 在USPO的某个地方,只有这样一张桌子。 而且,即使我们不承认它,那么COLLEGES.ZIPCODE和STUDENTS.ZIPCODE都是对该表的引用。

这与数据的哲学有关,而不是build立数据库的做法,但它巧妙地说明了一些根本性的东西:数据具有我们发现的特征,而不仅仅是我们发明的特征。 当然,我们发现的可能是别人发明的东西。 ZIPCODE确实如此。

PostgreSQL也拒绝这个(不pipe怎样,即使可能 ,这并不意味着这是一个好主意):

 essais=> CREATE TABLE Cities (name TEXT, country TEXT); CREATE TABLE essais=> INSERT INTO Cities VALUES ('Syracuse', 'USA'); INSERT 0 1 essais=> INSERT INTO Cities VALUES ('Syracuse', 'Greece'); INSERT 0 1 essais=> INSERT INTO Cities VALUES ('Paris', 'France'); INSERT 0 1 essais=> INSERT INTO Cities VALUES ('Aramits', 'France'); INSERT 0 1 essais=> INSERT INTO Cities VALUES ('Paris', 'USA'); INSERT 0 1 essais=> CREATE TABLE People (name TEXT, city TEXT REFERENCES Cities(name)); ERROR: there is no unique constraint matching given keys for referenced table "cities" 

我们在谈论什么数据库? 在SQL 2005中,我无法创build引用不具有唯一约束(主键或其他)的列的外键约束。

 create table t1 ( id int identity, fk int ); create table t2 ( id int identity, ); CREATE NONCLUSTERED INDEX [IX_t2] ON [t2] ( [id] ASC ); ALTER TABLE t1 with NOCHECK ADD CONSTRAINT FK_t2 FOREIGN KEY (fk) REFERENCES t2 (id) ; Msg 1776, Level 16, State 0, Line 1 There are no primary or candidate keys in the referenced table 't2' that match the referencing column list in the foreign key 'FK_t2'. Msg 1750, Level 16, State 0, Line 1 Could not create constraint. See previous errors. 

如果你真的可以做到这一点,你将有效地build立多对多的关系,这是不可能的,没有中间表。 我真的有兴趣听到更多关于这个…

看到这个相关的问题和答案。

Necromancing。
正如其他人已经说过,你不应该引用一个非唯一的密钥作为外键。
但是你可以做什么(没有删除级联危险)是添加一个检查约束(至less在MS-SQL中)。
这与外键不完全相同,但至less会防止插入无效/孤立/死亡数据。

请参阅此处以供参考(您必须将MS-SQL代码移植到MySQL语法中):
非主键的外键

编辑:
根据Mysql CHECK Constraint查找downvote的原因,MySQL并不真正支持CHECK约束。
你可以在你的DDL查询中定义它们的兼容性的原因,但他们只是被忽略…

但是正如在那里提到的那样,你可以创build一个BEFORE INSERTBEFORE UPDATE触发器,当数据的需求不被满足时,这将会抛出一个错误,这个错误基本上是一样的,除了它是一个更大的混乱。

至于这个问题:

我以为一个外键意味着一行必须引用一行,但我正在查看一些表,这是绝对不是这样的情况。

在任何健全的RDBMS中,这是事实。
这在MySQL中是可能的事实只是一个原因
MySQL是一个正常的RDBMS
这可能是快速的,但牺牲参考完整性和数据质量在速度的坛上并不是我的质量理念。
实际上,如果它不符合ACID标准,它根本就不是一个(正确运行的)RDBMS。