2014-05-25 65 views
1

我使用超级英雄为我的学校项目之一,我有一个超级英雄表(显然)和一个敌人表。所以敌人表有两个外键:有两个外键从一个主要来的表

bad_superhero_id 

good_superhero_id 

此表的目的是向好的超级英雄从字符表坏的超级英雄(他们的敌人)链接(超级英雄) 。这两个外键都取自超级英雄表的id。问题是我的老师不喜欢这个,我不知道为什么。我的意思是,我在一本名为的书中看到了这个例子。从PHP5开始,Apache和MySQL Web开发我也问过在创建数据库结构方面有丰富经验的同事。他们说这不是问题,但我的老师希望我给她举个例子,因为她不认为这是很好的关系,并希望我创建一个她认为的愚蠢的解决方法。我仍然认为这不是一种创造这种关系的不好方法,所以我想在这里问这个问题得到第三个意见。如果您提出您的意见,以便我能够理解这种使用这种关系的不好或不重要的做法,我将不胜感激。

编辑:

CREATE TABLE superhero (
    id INT NOT NULL AUTO_INCREMENT, 
    nick_name VARCHAR, 
    align ENUM ('good', 'bad'), 
    PRIMARY KEY(id) 
) ENGINE=INNODB; 

CREATE TABLE enemies_link (
    id INT NOT NULL AUTO_INCREMENT, 
    good_sh_id INT NOT NULL, 
    bad_sh_id INT NOT NULL, 
    PRIMARY KEY (id), 

    FOREIGN KEY (good_sh_id, bad_sh_id) 
     REFERENCES superheroes(id) 
     ON UPDATE CASCADE ON DELETE RESTRICT 
) ENGINE=INNODB; 

my database relationship

EDIT2:是的,我忘了补充一点,我想是N到N连接。比方说,蜘蛛侠对他的敌人有毒液和绿色妖精,另一方面,毒液还有其他一些好的超级英雄作为敌人,等等。

+2

请编辑您的文章并包含两张表的定义。谢谢。 –

+0

我不完全确定你的目标是什么。请包括表格定义 – SystemFun

+0

这张表格定义了什么样的关系?你的老师提倡的另一种方法是什么? – jsalonen

回答

1

您的设计本质上不是一个糟糕的设计,但它需要的工作。您正在使用定义n对n关系的交叉/交叉表。这些在生产数据库中一直使用,比如学生和课程之间的关系,学生可以参加几门课程,一门课程会让很多学生注册。你的意思是指双方同一张桌子。这也没关系。例如,一个零件表可以包含组件和模块,这些组件和模块包含用于制作多个模块的组件和由多个组件组成的模块。

在你的特殊情况下,你有一个标志,指明超级英雄是坏还是好。这很好(尽管“坏英雄”的概念有点颠簸 - 不会“超级”成为更好的称号吗?),但是标志和id必须在一个唯一的约束/索引中一起定义。这看起来可能是多余的,因为id是主键,因此它本身是唯一的。但是一个外键只能引用一个唯一的字段或一组字段。

至于交叉表,你真的不需要一个单独的ID字段。事实上,这会在数据完整性方面造成可能的裂痕。建模时,始终尝试将数据完整性作为主要因素。尽可能地将虚假数据放入表格中尽可能地做到这一点。表格键将全部作为外键字段作为一个大的组合键。如果按照 愚蠢的 设计标准要求单独的密钥,那么一定要将外键字段一起定义在唯一索引中。然后,你必须执行好/坏标志的值来确保'好'FK只能指向'好'超级英雄,等等。

CREATE TABLE superhero(
    id INT NOT NULL AUTO_INCREMENT, 
    nick_name VARCHAR(20), 
    align ENUM('good', 'bad') not null default 'good', 

    PRIMARY KEY(id), 
    constraint unique id_align_uq(id, align) 
) ENGINE=INNODB; 

CREATE TABLE enemies_link(
    good_sh_id INT NOT NULL, 
    good_align enum('good', 'bad') not null check(good_align = 'good'), 
    bad_sh_id INT NOT NULL, 
    bad_align enum('good', 'bad') not null check(bad_align = 'bad'), 

    PRIMARY KEY(good_sh_id, good_align, bad_sh_id, bad_align), 

    FOREIGN KEY(good_sh_id, good_align) 
    REFERENCES superhero(id, align) 
    ON UPDATE CASCADE ON DELETE RESTRICT, 

    FOREIGN KEY(bad_sh_id, bad_align) 
    REFERENCES superhero(id, align) 
    ON UPDATE CASCADE ON DELETE RESTRICT 
) ENGINE=INNODB; 
+0

非常感谢您的回答。我只是不明白你为什么在第二张桌子上有4个主键? –

+0

这不是4个主键,它是由4个字段组成的一个主键。它确保没有两个同一个好超级英雄与同一个坏超级英雄相关的行。这将是毫无意义的,也是一个设计缺陷 - 不止一次地允许同样的关系。 – TommCatt

2

你的老师可能是正确的:你很可能应该定义两个超级英雄和敌人的入侵检测系统作为单独的外键:

FOREIGN KEY good_sh_id REFERENCES superheroes(id), 
FOREIGN KEY bad_sh_id REFERENCES superheroes(id) 

您指定的语法,反而会指定的超级英雄作为参考a composite foreign key。我不得不承认我不确定这意味着什么。复合外键对我来说唯一的方法是当你使用它们来引用复合主键时。

+0

是的,我忘了补充一点,我想要n连接。比方说,蜘蛛侠对他的敌人有毒液和绿色妖精,另一方面,毒液有其他一些好的超级英雄作为敌人。 –

+0

编辑我的答案以反映您的更新。 – jsalonen

1

我认为你有正确的做法。我明白并可能重复你已经设计的例子。

table hero (in other words person) 
person_id, name, good_bad 

(顺便说good_bad可能会发生变化,所以考虑如果这是在正确的地方)

table opponent 
person_id, opponent_person_id, battlefield 

所以,你可以在不同的战场 不同的对手,你唯一的问题是保证双重条目或概念如何处理:例如;

person_id = 7, opponent_person_id = 11, battlefield = Rome 
person_id = 11, opponent_person_id =7, battlefield = Rome 

业务,这可能是一个现实的使用:

table employment 
chief_person_id,employe_person_id, department 
chief_person_id = 7, employe_person_id = 10, department= 1 
chief_person_id = 7, employe_person_id = 11, department= 1 
chief_person_id = 9, employe_person_id = 12, department= 2 
chief_person_id = 9, employe_person_id = 15, department= 2 
chief_person_id = 12, employe_person_id = 16, department= 2 (even sub-hierarchies can be shown. see id=12) 
相关问题