49

我认为外键意味着单行必须引用单行,但我正在查看一些绝对不是这种情况的表。Table1 的column1 对table2 的column2 有一个外键约束,但是table2 中有许多记录在column2 中具有相同的值。column2 上还有非唯一索引。这是什么意思?外键约束是否仅仅意味着至少一条记录必须存在正确的列中的正确值?我认为这意味着必须有一个这样的记录(不确定空值如何适合图片,但目前我不太关心这一点)。

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

4

7 回答 7

54

来自MySQL 文档

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

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

该文档进一步建议

未明确定义对非唯一键或包含 NULL 值的键的外键引用的处理 (...) 建议您使用仅引用 UNIQUE(包括 PRIMARY)和 NOT NULL 键的外键。

于 2010-02-01T19:15:31.707 回答
7

你的分析是正确的;键不必是唯一的,约束将作用于匹配行的集合。通常不是有用的行为,但可能会出现您想要的情况。

于 2009-02-26T01:36:28.107 回答
3

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

如果您确实使用了不指向主键的外键,那么出于性能考虑,您可能还希望为被引用的列创建一个(非唯一)索引。

取决于您使用的 RDBMS。我认为有些人会隐含地为您执行此操作,或者使用其他一些技巧。即时通讯。

于 2009-02-26T02:02:24.783 回答
3

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

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

如果我们快速检查

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

我们可能会发现这种关系是多对多的。如果我们的模式有一个名为 ZIPCODES 的表,主键为 ZIPCODE,那么真正发生的事情就很明显了。

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

这更多地与数据哲学有关,而不是构建数据库的实践,但它巧妙地说明了一些基本的东西:数据具有我们发现的特征,而不仅仅是我们发明的特征。当然,我们发现的可能是其他人发明的。ZIPCODE 肯定是这种情况。

于 2009-02-26T06:20:54.070 回答
1

PostgreSQL 也拒绝了这一点(无论如何,即使有可能,也不代表这是一个好主意):

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"
于 2009-02-26T13:09:52.980 回答
1

死灵术。
正如其他人已经说过的那样,您不应该将非唯一键引用为外键。
但是你可以做的(没有删除级联危险)是添加一个检查约束(至少在 MS-SQL 中)。
这与外键并不完全相同,但至少它可以防止插入无效/孤立/死数据。

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

编辑:
根据Mysql CHECK Constraint搜索不赞成票的原因,MySQL 并不真正支持 CHECK 约束。
出于兼容性原因,您可以在 DDL 查询中定义它们,但它们只是被忽略...

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

至于问题:

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

在任何健全的 RDBMS 中,都是如此。这在 MySQL 中是可能的这一事实只是MySQL 是一个疯狂的 RDBMS 的
另一个原因。 它可能很快,但在速度的祭坛上牺牲参照完整性和数据质量并不是我对质量 rdbms 的想法。 事实上,如果它不符合 ACID,那么它根本就不是一个(正常运行的)RDBMS。


于 2014-10-17T15:12:08.367 回答
0

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

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.

如果您真的可以做到这一点,您将有效地建立多对多关系,如果没有中间表,这是不可能的。我真的很想听到更多关于这个的信息......

另请参阅此相关问题和答案。

于 2009-02-26T02:21:49.167 回答