PK和FK表设计之间的混淆

Posted

技术标签:

【中文标题】PK和FK表设计之间的混淆【英文标题】:Confusion between PK and FK table design 【发布时间】:2017-12-30 08:28:59 【问题描述】:

我有一个person 表和一个score 表。 Person 表基本上存储了一个人的信息,而score 表存储了一个人的分数。我将score表中的FK约束设置为ON DELETE: CASCADE

person
- id
- name
- scored_id (FK)

score
- id (PK)
- bmi
- weight

因此,在表格设置中score.id 与人的scored_id 相关联。也就是说,当我删除score 中的记录时,一个人也会被删除。但是为什么我删除person中的一条记录,他的in score的记录并没有被删除?

【问题讨论】:

能否包含用于创建这些表的脚本 除非您使用外键进行循环依赖,否则这通常是野兽的本性 - 单向依赖 您的外键设置似乎不正确。按照@NigelRen 的说明发布脚本。 @NigelRen 那是为了什么?我上面的表格显示的关系还不够清楚吗? @Kiwagi 真的吗?这里有什么问题?我的表结构正确吗? 【参考方案1】:

只是一个想法,您可以如何构造表并使用外键,如果/当删除人员表中的用户时,该外键将从分数表中删除记录。 score 表应该有一个对用户的引用——pid,它被用作外键依赖。对我来说,分数取决于用户是有道理的,所以没有用户,就没有分数。

create table `person` (
    `id` int(10) unsigned not null auto_increment,
    `name` varchar(50) null default null,
    primary key (`id`)
)
collate='latin1_swedish_ci'
engine=innodb
auto_increment=4;


mysql> describe person;
+-------+------------------+------+-----+---------+----------------+
| Field | Type             | Null | Key | Default | Extra          |
+-------+------------------+------+-----+---------+----------------+
| id    | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| name  | varchar(50)      | YES  |     | NULL    |                |
+-------+------------------+------+-----+---------+----------------+




create table `score` (
    `id` int(10) unsigned not null auto_increment,
    `bmi` int(10) unsigned not null default '0',
    `weight` int(10) unsigned not null default '0',
    `pid` int(10) unsigned not null default '0',
    primary key (`id`),
    index `pid` (`pid`),
    constraint `fk_sc_pid` foreign key (`pid`) references `person` (`id`) on update cascade on delete cascade
)
collate='latin1_swedish_ci'
engine=innodb
auto_increment=4;



mysql> describe score;
+--------+------------------+------+-----+---------+----------------+
| Field  | Type             | Null | Key | Default | Extra          |
+--------+------------------+------+-----+---------+----------------+
| id     | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| bmi    | int(10) unsigned | NO   |     | 0       |                |
| weight | int(10) unsigned | NO   |     | 0       |                |
| pid    | int(10) unsigned | NO   | MUL | 0       |                |
+--------+------------------+------+-----+---------+----------------+





mysql> select * from person;
+----+------+
| id | name |
+----+------+
|  1 | bob  |
|  2 | rita |
|  3 | sue  |
+----+------+


mysql> select * from score;
+----+-----+--------+-----+
| id | bmi | weight | pid |
+----+-----+--------+-----+
|  1 |  34 |     34 |   1 |
|  2 |  56 |     41 |   2 |
|  3 |  56 |     77 |   3 |
+----+-----+--------+-----+



mysql> delete from person where id=3;
Query OK, 1 row affected (0.00 sec)

/* delete a user, the score disappears too which makes sense */

mysql> select * from score;
+----+-----+--------+-----+
| id | bmi | weight | pid |
+----+-----+--------+-----+
|  1 |  34 |     34 |   1 |
|  2 |  56 |     41 |   2 |
+----+-----+--------+-----+

【讨论】:

是的,有道理,我的结构首先是错误的 一般来说,数据库设计在第一次尝试时很少“准确”——随着您对将要发生的事情以及如何操作等有了更清晰的了解,您可以在这里和那里进行一些小的调整。希望以上和其他注释/建议有所帮助。 加我十个。 @Madeline Ries,值得看看我的答案,因为我认为它有助于补充 RamRaiders 的叙述性解释。祝你申请顺利。【参考方案2】:

您的问题是对任务的语义理解,而不是语法。直觉上你的关系看起来不对。一个特定的分数,比如 75 公斤和 20 的 bmi 不太可能需要与具有相同分数的人有许多关系链接。这将是任意的。更有可能的是,您希望一个人随着时间的推移具有不同的分数,然后当您删除一个人时,您希望删除他们的关联值。所以表关系应该是:

person
- id (Primary Key)
- name

score
- id (Primary Key)
- bmi
- weight
- scoreDate
- personID (Foreign Key to person)

分数日期将是一个有用的补充。

这种结构将允许一个人拥有许多分数的历史,并查看他们的体重和体重指数随时间的波动。与现实产生共鸣的语义上有用的任务,因此遵循实体分析和表结构的概念,遵循现实世界的应用。

Helpful discussion of ERD and table structure levels and relations

【讨论】:

【参考方案3】:

在您的表中,“person”表具有“score”表的引用(FK),因此当您删除“score”表中的记录时,mysql 搜索“users”表中的相关记录以删除。

但是“score”表没有“person”表的任何引用(FK)。

如果你想在删除个人记录时删除分数记录,你可以尝试下面的表格结构,但如果删除分数记录,个人记录仍然是安全的

person
- id (PK)
- name

score
- id (PK)
- person_id (FK)
- bmi
- weight

【讨论】:

以上是关于PK和FK表设计之间的混淆的主要内容,如果未能解决你的问题,请参考以下文章

多对多关联表PK作为其他表中的FK

如何在 SQL Server 中复制表(包括 PK 和 FK)

表 A 的 PK 被表 B 的 FK 引用。不能掉表A的PK

是否可以在实体框架中将表FK链接到另外两个PK?

如何禁用和启用表 mysql 中的所有约束,包括。 PK FK CHK UNI 等

数据字典的设计