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表设计之间的混淆的主要内容,如果未能解决你的问题,请参考以下文章
如何在 SQL Server 中复制表(包括 PK 和 FK)
表 A 的 PK 被表 B 的 FK 引用。不能掉表A的PK