【问题标题】:Need some advice and feedback on coding a many:many relationship in MySQL需要一些关于在 MySQL 中编写多:多关系的建议和反馈
【发布时间】:2012-05-07 21:32:36
【问题描述】:

我在编写多对多关系时遇到了一些困难,如下图所示:

我希望设置这些表和关系,以便:

  • 父母可以有多个孩子(这里的孩子是 “玩家”),一个孩子可以有一个或多个父母(最多 二)。
  • “家庭”可以由一个或多个父母(最多两个)组成, 以及一个或多个孩子(不限)。

我不知道如何容纳与他们的“孩子”姓氏不同的父母,反之亦然。我还没有被告知这是否会成为一个问题,但我认为这是值得考虑的事情。 Parent 和 Player 类都从 person 超类继承字段(例如名字和姓氏、地址、年龄、d.o.b 等)。

当我意识到我不确定如何插入一个或多个父母与他们是父母(或看护人)的一个或多个孩子时,我正要测试一些输入到家庭表中。我以为我在理论上已经解决了这个问题,但在测试后我意识到它不起作用,我花了 90 多分钟为一些想法画草图,但我真的迷路了。

============================================== =======================================

更新:27-04-2012 @ 22:19PM NZST

当查询包含这些表的数据库时,我应该给出我正在寻找的结果的可视化表示。这是视觉表示:

+-------------------+-----------------+---------------------+
| ParentsFirstName  | ParentsLastName | ChildrenInFamily    |
+-------------------+-----------------+---------------------+
| Gregory           | Peck            | Michael             |
| Laura             | Peck            | Michael             |
| Martha            | Petersen        | Matt, Christopher   |
| Chris             | Michaels        | Richard, Shaun      |
| Nadine            | Michaels        | Richard, Shaun      |
| Barry             | Dackers         | Harry               |
| Kevin             | Mitchell        | Daniel              |
| Rebecca           | Mitchell        | Daniel              |
+-------------------+-----------------+---------------------+

“孩子”在名为“玩家”的表中,父母在名为“父母”的表中。这篇文章中的 MySQL 代码代表了关于这个特定问题的表(你应该注意到我使用 Person 类作为超类,而父/子表作为子类)。其他一些表是通过使用外键引用的(“schoolID”字段来自名为“School”的表,该表有一个“schoolName”字段)。

我不确定我构建的表是否适合我想要实现的目标,但在做一些研究时,我发现了一个名为 GROUP_CONCAT 的函数,它至少让我想到了查询可能是什么样的 -针对这个特殊问题。

容纳不同姓氏的父母,以及与父母不同姓氏的孩子,是我什至无法解决的另一个重大挑战(我' d 想象寄养家庭也是如此)。因此,对于上述可视化,我假设非单亲父母已婚并具有相同的姓氏,并且孩子都与已婚父母的姓氏相同。

============================================== =======================================

这是我尝试创建的数据库部分的一些代码,试图处理这部分(注意:“玩家”是父母的“孩子”):

DROP TABLE IF EXISTS `person` ;
CREATE TABLE `person` (
  `personID` INT(5) NOT NULL AUTO_INCREMENT ,
  `firstName` VARCHAR(50) NOT NULL ,
  `lastName` VARCHAR(50) NOT NULL ,
  `dateOfBirth` DATE NOT NULL ,
  `personType` CHAR(6) NOT NULL, 
  `photo` BLOB NULL DEFAULT NULL ,
  PRIMARY KEY (`personID`))
ENGINE = InnoDB;
SHOW WARNINGS;

DROP TABLE IF EXISTS `parent` ;
CREATE TABLE `parent` (
  `parentID` INT(5) NOT NULL,
  FOREIGN KEY (`parentID`) REFERENCES `person` (`personID`)
  ON DELETE CASCADE 
  ON UPDATE CASCADE)
ENGINE = InnoDB;
SHOW WARNINGS;

DROP TABLE IF EXISTS `player` ;
CREATE TABLE `player` (
  `playerID` INT(5) NOT NULL, 
  `schoolID` INT(5) NOT NULL,
    FOREIGN KEY (`playerID`) 
    REFERENCES `person` (`personID`)
    ON DELETE CASCADE 
    ON UPDATE CASCADE, 
    FOREIGN KEY (`schoolID`)
    REFERENCES `school` (`schoolID`)
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;
SHOW WARNINGS;

DROP TABLE IF EXISTS `family` ;
CREATE TABLE `family` (
  `parentID` INT(5) NOT NULL ,
  `playerID` INT(5) NOT NULL ,
  PRIMARY KEY (`parentID`, `playerID`), 
    FOREIGN KEY (`playerID` )
    REFERENCES `player` (`playerID`)
    ON DELETE CASCADE
    ON UPDATE CASCADE,
    FOREIGN KEY (`parentID`)
    REFERENCES `parent` (`parentID`)
    ON DELETE CASCADE
    ON UPDATE CASCADE)
ENGINE = InnoDB;
SHOW WARNINGS;

如果有人可以通过提供一些指导,甚至是一些带有解释的通用示例来帮助我解决这个问题,那就太好了。我认为这是一个多对多的关系,我不能完全放弃,因为父母可以有一个或多个孩子,一个孩子可以有一个或多个父母(在这种情况下,一个家庭不会是一个没有孩子的家庭)。

提前非常感谢!!!

【问题讨论】:

  • 如何将family 表扩展为第二个父级的另一列?
  • @mrab 你能更全面地解释一下吗?我正在使用“父”表中的外键链接“家庭”表,那么我将如何在这里满足至少两个父母的需求?

标签: mysql sql database database-design relational-database


【解决方案1】:

好吧,这太痛苦了。你把它复杂化了。我没有 visio,所以请尝试应对:

  • PERSON(person_id, first_name, last_name) PK: person_id
  • FAMILY(parent,player) PK:(parent,player) FK:FAMILY.parent -> PERSON.person_id, FK:player->PERSON.person_id

就是这样 - 很简单。

您所需要的只是一张将两个不同的人匹配在一起的表格。要找到孩子的所有看护人,您只需将个人加入并筛选孩子即可。

地址:

  • PERSON_ADDRESS(person_id,address_id) PK:(person_id,address_id) FK:person_id->person.person_id, FK:address_id->address.address_id
  • ADDRESS(address_id,st-num,street, city,phone) PK:address_id 其中 st-num 可能是 23B 之类的字母数字

实际上 - 我不喜欢你把电话放在地址里。不会扩展到地址中的多个电话号码。但是地址是一种干扰。您的问题似乎是关于将玩家与父母联系起来。

学校应该是它自己的桌子。要么将 school_id 放入 person 中,要么如果您讨厌空值,则有一个连接表 person_school,它只包含孩子们的记录

【讨论】:

    【解决方案2】:

    我不确定为什么一个人会有多个地址 - 但我想他们可以。但是,如果我正在处理多个地址,那么我会将地址推送到另一个表中并有一个 person_address 加入表。这样一来,您就不会为居住在同一地址的每个人重复地址数据。

    您的父表需要两个字段 - 一个用于父级,另一个用于播放器(正如我之前所说的 BOTH 我认为如果它们都指向人会更好)。为什么你在 paren 和 player 之间有两条关系线?

    person|parent 关系不会是 1..1 - 1..1,因为这意味着每个人都是父母,而您的玩家可能不是。

    顺便说一句——但你似乎真的很关注父母。可能没有任何一个,也可能有多个。您不需要单独的关系来规定性别 - 这应该是 PERSON 中的数据,或者根本不存在无关紧要的数据。

    【讨论】:

      【解决方案3】:

      我不确定这本身是否是一个“答案”,但这是我尝试调整我的 MySQL 代码以适应 Branko Dimitrijevic 的答案为我提供的内容。这是我为相关表调整的 MySQL 代码:

      DROP TABLE IF EXISTS `person` ;
      CREATE TABLE `person` (
        `personID` INT(5) NOT NULL AUTO_INCREMENT ,
        `firstName` VARCHAR(50) NOT NULL ,
        `lastName` VARCHAR(50) NOT NULL ,
        `dateOfBirth` DATE NOT NULL ,
        `personType` CHAR(6) NOT NULL, 
        `photo` BLOB NULL DEFAULT NULL ,
        PRIMARY KEY (`personID`))
      ENGINE = InnoDB;
      SHOW WARNINGS;
      
      DROP TABLE IF EXISTS `parent` ;
      CREATE TABLE `parent` (
        `parentID` INT(5) NOT NULL,
        PRIMARY KEY (`parentID`), 
        FOREIGN KEY (`parentID`) REFERENCES `person` (`personID`) 
        ON DELETE CASCADE 
        ON UPDATE CASCADE)
      ENGINE = InnoDB;
      SHOW WARNINGS;
      
      DROP TABLE IF EXISTS `player` ;
      CREATE TABLE Player (
          `playerID` INT(5) NOT NULL,
          `motherID` INT(5),
          `fatherID` INT(5),
          `schoolID` INT(5),
          PRIMARY KEY (`playerID`), 
          FOREIGN KEY (`playerID`) REFERENCES `person` (`personID`) 
          ON DELETE CASCADE 
          ON UPDATE CASCADE,
          FOREIGN KEY (`motherID`) REFERENCES `parent` (`parentID`) 
          ON DELETE CASCADE 
          ON UPDATE CASCADE,
          FOREIGN KEY (`fatherID`) REFERENCES `parent` (`parentID`) 
          ON DELETE CASCADE 
          ON UPDATE CASCADE, 
          FOREIGN KEY (`schoolID`) REFERENCES `school` (`schoolID`) 
          ON DELETE CASCADE 
          ON UPDATE CASCADE)
      ENGINE = InnoDB;
      SHOW WARNINGS;
      

      这是包含这些表格的逻辑模型的一部分:

      如果布兰科或其他任何人可以用布兰科的回答来验证我的尝试,那就太好了。您还会注意到,对于图像,我使用 MySQL Workbench 作为模型。

      以下内容超出了这个特定问题的范围,但如果有人可以帮助解决这个问题,那就太好了:

      我被要求不要使用反向或正向工程将 sql 代码转换为模型架构等,但这使我能够验证我在 Visio 中构建的模型的正确性。但是,我不能完全让 Visio 模型看起来像 Workbench 模型 - 这是我试图在上面建模的表的 Visio 版本:

      正如您在 Visio 版本中看到的那样,“fatherID”和“motherID”列未指示为外键,这是我想要的(在 Workbench 版本中进行了说明)。如果有人可以帮助我让我的 Visio 模型看起来与 Workbench 版本相同,那就太好了。

      【讨论】:

        【解决方案4】:

        您只需要一个包含两个字段的连接表:孩子、看护人。这基本上就是你的“家庭”表 - 我不明白你的“父母”表的目的。 “family”中的BOTH 值将是“person”的外键(即,使“player”成为比图表中更通用的表。)

        这样就可以让任何孩子拥有任意数量的看护人。任何照顾者都可以与任何数量的孩子联系在一起。不正当和美妙的家庭安排的所有可能组合都被容纳了。

        【讨论】:

          【解决方案5】:

          我完全会质疑家庭实体的使用。一个孩子可以通过父母的离婚和随后的再婚成为两个家庭的成员——你会如何建模?一个孩子可能没有四个人有效地“代替父母”行动吗?

          【讨论】:

            【解决方案6】:

            一个孩子不能有超过 2 个父母,他们都有特定的角色(母亲与父亲),并且可能存在一个或两个父母都不知道的情况。

            所以这不是真正的“多对多”关系,它实际上是“多对零或一或二”,可以这样自然地表示(MotherIDFatherID 都可以为 NULL) :

            如果您将LastName 放在ParentPlayer 中(或者在您的情况下是一个共同的超类),这自然也涵盖了父母与孩子姓氏不同的情况。

            然后您可以像这样轻松获得“每个父母的孩子”(SQL Fiddle)...

            SELECT
                ParentID,
                Parent.FirstName ParentFirstName,
                Parent.LastName ParentLastName,
                PlayerID,
                Player.FirstName PlayerFirstName,
                Player.LastName PlayerLastName
            FROM
                Parent
                LEFT JOIN Player
                    ON Parent.ParentID = Player.MotherID
                    OR Parent.ParentID = Player.FatherID
            ORDER BY ParentId
            

            ...如果您愿意,可以在您的应用程序代码中转换数据。


            上述模型允许Parent 的性别与其母亲/父亲角色不匹配。如果你想防止这种情况发生,你可以做得太过火,做这样的事情......

            ...但我宁愿不复杂化并坚持使用第一个模型并在应用程序级别强制执行。

            【讨论】:

            • “一个孩子不能有超过 2 个父母,他们都有特定的角色(母亲与父亲)” 除非我们有收养。或者gay marriage 是允许的:)
            • @ypercube 当然可以,但是我们可以简单地将一个父级声明为“父级 1”,将另一个父级声明为“父级 2”,然后继续前进,而无需从根本上改变逻辑。唯一的问题是,如果我们想模拟一个可能有超过 2 个“父母”的情况(例如,我们想要计算亲生父母和养父母) - OP 将必须决定这种情况是否足够可能和足够重要以证明模型复杂化是合理的。
            • 我并不是说——无论如何——你的回答是无效的。只是想找个借口添加该链接。它有一个相当不错的关于模拟婚姻家庭关系的选项列表。
            • @BrankoDimitrijevic 感谢您的反馈,这为我提供了解决此问题所需的信息:)。我的数据库中还有其他一些 many:many,这可能会解决潜在问题。
            【解决方案7】:

            实现多对多关系的 Family 表通常是在用户输入 Parent/Player(s) 数据之后创建的。 UI 通常被描述为主窗体/子窗体组合,其中父窗体从主窗体中输入/选择,并且与父窗体关联的一个或多个玩家在子窗体中输入/显示;通常是某种网格。

            【讨论】:

            • 非常感谢您的反馈 :)。虽然我只使用命令行作为“界面”......我只使用 MySQL 来解决这个特定问题。我想要实现的是让家庭表(两个“许多”表之间的链接表)为每个父母提供两列 - 一个是强制性的,然后是能够拥有无限数量的孩子的东西. 因为其中一个父母是可选的,所以我不能将它们一起用作主键。
            • ...另外,我真的不希望出现每个子记录都有重复列表的情况。
            • 大家好,我刚刚看到了这个链接:dougboude.com/blog/1/2009/12/… - 这给了我一些线索,但仍然可以随时提供帮助...
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-04-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-01-19
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多