微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

MySQL:非唯一列的 FK

如何解决MySQL:非唯一列的 FK

出乎我的意料,MysqL 允许对非唯一列进行 FK。我不确定这是否也适用于其他数据库,并且一直认为 FK 必须是唯一的 - 否则,我们如何知道子行的父行 - 但看起来情况并非如此. Here 是说明这一点的小提琴。我们首先创建 3 个表:

CREATE TABLE competitions(
         cID INT UNSIGNED AUTO_INCREMENT,title text not null,primary key (cid)
     ) engine=innodb CHaraCTER SET utf8mb4;
 
 create table teams (
         tID INT UNSIGNED AUTO_INCREMENT,cid int unsigned not null,name varchar(24) not null,primary key (tid),foreign key (cid) references competitions(cid)
     ) engine=innodb CHaraCTER SET utf8mb4;
 
create table users (
         row_id int unsigned auto_increment,uID INT UNSIGNED not null,tid int unsigned not null,primary key (row_id),unique key (cid,uid),foreign key (tid) references teams(tid),foreign key (cid) references teams(cid)  /* refers to non-unique column */
    ) engine=innodb CHaraCTER SET utf8mb4;

然后我们可以运行以下 INSERT 命令:

insert into competitions (title) values ('olympics 2020'),('wimbledon 2021'),('
ICC world cup 2022');

/* insert duplicate values in cid column.  */
insert into teams(cid,name) values (1,'usa'),(1,'china'),(2,'germany'),'france'),(3,'india'),'england');

/* the cid is a FK and is not unique in the parent table but MysqL does not complain! */
insert into users (cid,tid,uid) values (1,1,1);

我的问题是 (1,1) 的父行是谁? teams 表中有两行带有 cid=1

解决方法

外键关系不是定义“父”关系。简单来说就是键值的组合存在于另一个表中。

在实践和 SQL 定义中,引用的值应该是唯一的(最好是主键)。这在几乎所有数据库中都是必需的。

MySQL 扩展了这个定义以允许任何索引列。

,

这是 InnoDB 实现的一个特点。外键列必须引用任何索引的最左边的列。如您所见,您可以使其引用非唯一索引。

你也可以让它引用唯一索引中最左边的列子集:

create table parent (id1 int,id2 int,primary key (id1,id2));

create table child (id1 int,foreign key (id1) references parent(id1) on delete cascade);

但这是非标准的,并且与其他 SQL 数据库不兼容。它带来了令人不安的问题:

mysql> insert into parent values (1,1),(1,2);
mysql> insert into child values (1);
mysql> delete from parent where id1=1 and id2=1;
mysql> select * from child;
Empty set (0.00 sec)

似乎如果删除外键引用的任何行,那么这会导致删除级联。这是想要的吗?即使父级中仍然存在满足外键引用的行?

mysql> select * from parent;
+-----+-----+
| id1 | id2 |
+-----+-----+
|   1 |   2 |
+-----+-----+

尽管 InnoDB 允许这样做,但我强烈建议您不要将表设计为依赖它。继续让外键只引用主键或唯一键,并且只引用这些键的完整列。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。