如何引用关系数据库中的记录组?

How to reference groups of records in relational databases?

假设我们有以下table结构:

人类

| HumanID | FirstName | LastName | Gender |
|---------+-----------+----------+--------|
|       1 | Issac     | Newton   | M      |
|       2 | Marie     | Curie    | F      |
|       3 | Tim       | Duncan   | M      |

动物

| AmimalID | Species | NickName |
|----------+---------+----------|
|        4 | Tiger   | Ronnie   |
|        5 | Dog     | Snoopy   |
|        6 | Dog     | Bear     |
|        7 | Cat     | Sleepy   |

我想知道如何引用其他 table 中的一组记录。

例如,我有一个 Foods table 和一个 EatenBy 列。

食物

| FoodID | FoodName | EatenBy |
|--------+----------+---------|
|      8 | Rice     | ???     |

我想存入EatenBy的可能是

  1. 人类、动物 table 中的单个记录(例如,Tim Ducan)
  2. 一组记录在一个table中(例如所有狗,所有男性,所有女性)
  3. 一个整体table(例如所有人类)

一个简单的解决方案是使用 连接字符串 ,其中包括主键 来自不同的 table 和特殊字符串,例如 'Humans'、'M'。 应用程序可以解析连接的字符串并相应地执行操作。

食物

| FoodID | FoodName | EatenBy      |
|--------+----------+--------------|
|      8 | Rice     | Humans, 6, 7 |

我知道从 关系数据库设计。

另一种选择是添加另一个 table 并使用 外键

食物

| FoodID | FoodName |
|--------+----------|
|      8 | Rice     |

EatenBy

| FoodID | EatenBy |
|--------+---------|
|      8 |  Humans |
|      8 |       6 |
|      8 |       7 |

我认为它比第一个解决方案更好。问题是 EatenBy 字段存储了不同含义的值。有问题吗?

对此需求建模的最佳方法是什么?这种情况下如何实现3NF?

这里的例子 table 有点做作,但我确实 运行 遇到这样的情况 这在工作中。我已经看到很多 tables 只是使用一个连接的字符串。我认为这很糟糕,但想不出更关系的方式来处理它。


快速回答

对于那些想快速知道这个问题的答案的人。以下是基本思路:

  1. 不应在关系模型中使用串联字符串、CSV、重复组。所以我们需要规范化 table,消除重复组。
  2. 在这道题中,连接的字符串包含不同含义的值。
    关系数据库存储关于现实世界的事实。每个 table 应该存储关于一个主题的事实,每一列应该存储 一个事实.
    因此,我们需要一个联想table来修复“EatenBy”的每个事实。
    例如
    Food_Human (FoodID, HumanID)
    Food_Animal (FoodID, AnimalID)
    Food_Species(食品 ID、物种 ID)

警告

解决问题的思路不错。但是,这里的数据模型很糟糕。

明显的问题:

  1. 人是动物
  2. 在数据建模期间使用代理项 (ID) 是不好的做法
  1. 本回答按时间顺序排列。该问题在细节方面取得了进展,记为 更新。有一系列匹配的 Responses

  2. 从最初的问题到最终答案的过程是一种学习经历,尤其是对于 OO/ORM 类型。大标题标为 Responses,小标题标为 subjects。

  3. 答案超出最大长度。我将它们提供为 links 以克服这个问题。

对最初问题的回应

你可能在工作中看到过类似的东西,但这并不意味着它是正确的,或者接受table。 CSV 打破 2NF。您无法轻松搜索该字段。您无法轻松更新该字段。您必须通过代码手动管理内容(例如,避免重复;排序)。您没有数据库或类似数据库的任何东西,您有一个宏伟的记录归档系统,您必须向 "process" 编写堆积如山的代码。就像 1970 年代 ISAM 数据处理的糟糕日子一样。

  1. 问题是,您似乎需要一个关系数据库。也许您已经听说过数据完整性、关系的力量(在这个阶段为您加入力量)和速度。记录归档系统有 none 个。

    如果你想要一个关系数据库,那么你将不得不:

    • 从关系的角度考虑数据,并应用关系数据库方法,例如将数据建模为数据,仅数据(而不是数据值)。

    • 然后 class 化数据(与 OO class 或 classifier 概念无关)。

    • 然后关联class化数据

  2. 第二个问题是,这是典型的 OO 类型,他们专注于、痴迷于数据 values,而不是意义数据;它是如何 class 化的;它与其他数据的关系;等等

    没问题,你自己没有想到这个概念,你的 "teachers" 把它喂给了你,我一直都看到它。他们 喜欢 记录归档系统。请注意,您没有给出 table 定义,而是声明给出了 "structure",而是列出了数据值。

    • 如果你不明白我在说什么,让我向你保证,这是 OO 世界中的一个 classic 问题,解决方案很简单,如果你应用原则。否则在 OO 堆栈中将是一个无穷无尽的混乱。最近我完全取消了一个 OO proposal + solution 一个支持 OO monolith 的非常著名的数学家提出的。这是一篇著名的论文。

    • relationalised 数据(即我只是将数据放在关系上下文中:对其进行建模和规范化,总共花费了十分钟),问题就消失了,不需要提案+解决方案。阅读Hidders Response。请注意,我 不是 试图破坏论文,我试图理解以精神分裂症形式呈现的数据,最简单的方法是建立关系数据模型.那个简单的动作毁了那张纸。

    • 请注意,link 是澳大利亚一家大型银行客户付费任务的正式报告的摘录,该银行已允许我发布摘录旨在教育 public 忽略关系数据库原则的危险,尤其是 OO 支持者。

    • 第二篇更著名的论文 Kohler Response 也发生了完全相同的过程。这种回应要小得多,不那么正式,它不是为客户做的有偿工作。那个作者正在理论化另一个异常 "normal form".

因此,我想请您:

  • 忘记 "table structures" 或定义

  • 忘乎所以

  • 忘记实现选项

  • 忘记 ID 列,完全彻底

  • 忘记了EatenBy

  • 想想你的数据,数据的意义,不是作为数据值或示例数据,不是你想用它做什么

  • 想想这些数据是如何class化的,以及如何class化的。

  • 数据与其他数据的关系。 (您可能认为您的 EatenBy 是,但事实并非如此,因为数据还没有组织,以形成关系。)

如果我看看我的 crystal 球,它的大部分是黑暗的,但从我能看到的小光点来看,它看起来像你想要的:

  • 东西

  • 事物组

  • 事物与事物组之间的关系

事物是名词、主语。最终我们将在这些主题之间做一些事情,这将是动词或动作陈述。这将形成谓词(一阶逻辑)。但不是现在,现在,我们只想要 Things。

现在,如果您可以修改您的问题并告诉我更多关于您的事物及其含义的信息,我可以为您提供完整的数据模型。


响应层次结构更新 1

记录 ID 是物理的,Non-relational

如果你想要一个关系数据库,你需要关系键,而不是记录 ID。此外,开始数据建模练习时在每个文件上都标记一个 ID 会使练习瘫痪。

请阅读this Answer

数据中存在层次结构

如果你想要一个完整的讨论,请提出一个新问题。这是一个快速摘要。

世界上自然存在等级制度,它们无处不在。这导致在许多数据库中实现层次结构。 关系模型 建立在层次模型 的基础之上,并且是其发展。它出色地支持层次结构。不幸的是,著名作家不理解 RM,他们只教授标记为 "relational" 的 1970 年代之前的记录归档系统。同样,他们不理解层次结构,更不用说 RM 支持的层次结构了,所以他们压制它。

其结果是,必须实施的无处不在的层次结构没有被识别出来,因此它们的实施方式非常不正确且效率极低。

相反,如果正在建模的数据中出现的层次结构被正确建模,并使用真正的关系结构(关系键、规范化等)实现,则结果是 easy-to-use 和 easy-to-code 数据库,并且没有数据重复(以 any 形式)并且速度非常快。从字面上看,它是最好的关系。

数据中存在三种层次结构。

  1. 按 Tables

    顺序形成的层次结构

    这个要求,关系键的需要,出现在每个数据库中,相反,缺少它会削弱数据库广告产生一个记录归档系统,具有 none 关系数据库的完整性、功能或速度。

    层次结构以关系键的形式清晰可见,关系键以任何 tables 的顺序复合:父亲、儿子、孙子等。这对于普通关系数据完整性至关重要,Hidders 和 95% 的数据库实现都没有的那种。

    Hidders Response 有一个很好的层次结构示例:

    一个。自然存在于数据中

    b。 OO 类型是盲目的 [因为 Hidders 显然是]

    c。他们实施不完整的 RFS,然后他们尝试 "fix" object 层中的问题,甚至增加 更多 复杂性。

    虽然我以 classic 关系形式实现了层次结构,但问题完全消失了,删除了建议的 "solution" 论文。 Relational-isation 消除理论。

    这四个 table 中的两个层次结构是:

        Domain::Animal::Harvest
    
        Domain::Activity::Harvest
    

    请注意,Hidders 不知道数据是层次结构这一事实;他的 RFS 不具有完整性正是因为它不是关系型的;将数据放在关系上下文中提供了他在它之外寻求的完整性;关系模型消除了所有这些 "problems",并使所有这些 "solutions" 变得可笑。

    这里是another example,虽然建模还没有完成。请确保检查谓词和第 2 页的实际键。层次结构是:

        Subject::CategorySubject::ExaminationResult
    
        Category::CategorySubject::ExaminationResult
    
        Person::Registrant::Candidate::ExaminationResult
    

    请注意,最后一个是业务工具状态的进展,因此密钥不会复合。

  2. 一个行内的层次结构Table

    通常是某种树结构,实际上有数百万个。对于任何给定的节点,这都支持单个祖先或 parent,并且不受限制 children。如果做得好,层数或树的高度没有限制(即无限的祖先和后代)。

    • 这里使用的术语祖先后代是普通的技术术语,它们没有面向对象的内涵和限制。

    您确实需要在服务器中进行递归,以便遍历树结构,以便您可以编写递归的简单过程和函数。

    这是 Messages. Please read both the question and the Answer, and visit the linked Message Data Model 的一个。注意求助者没有提到Hierarchytree因为关系数据库中Hierarchy的知识被压制了,但是(从评论中)一旦他看到答案和数据模型,他就认出了它的层次结构,并且它非常适合他。层次结构是:

        Message::Message[Message]::Message[::Message[Message]] ...
    
  3. 一个行中的层次结构 Table,通过关联 Table

    此层次结构为多个祖先或 parent 提供了一个 ancestor/descendant 结构。它需要两个关系,因此需要一个额外的 Associative Table。这通常称为物料清单结构。不限高度,递归遍历

    物料清单问题 是分层 DBMS 的一个限制,我们在网络 DBMS 中部分克服了这个问题。这在当时是一个紧迫的问题,也是 IBM 的具体问题之一,E F Codd 博士被明确要求解决。当然,他实现了这些目标,并且惊人地超越了它们。

    这里是Bill of Materials hierarchy, modelled and implemented correctly

    • 序言请见谅,来自一篇文章,跳过上面两行,看下面一行。

    • Person::Progeny 也给出了。

    • 层次结构为:

      Part[Assembly]::Part[Component] ...
      
      Part[Component]::Part[Assembly] ...
      
      Person[Parent]::Person[Child] ...
      
      Person[Child]::Person[Parent] ...
      

不了解等级制度

与层次结构通常存在于数据中这一事实不同,由于抑制,它们未被识别为层次结构,因此它们未作为层次结构实现,当它们 被认可,它们以最荒谬的方式实施,ham-fisted 方式。

  • 邻接表

    镇压者滑稽地说 "the Relational Model doesn't support hierarchies",否认它是建立在 层次模型 之上的(每个模型都提供了明显的证据表明他们不知道基本的RM 中的概念,他们声称这些概念是假设的)。所以他们不能使用这个名字。这是他们使用的愚蠢名称。

    一般来说,实现会认识到数据中存在层次结构,但实现会很差,受限于物理记录 ID 等,缺乏关系完整性等

    而且他们对如何遍历树一无所知,需要递归。

  • 嵌套集

    堕胎,直接来自地狱。记录归档系统中的记录归档系统。这不仅会产生大量重复并破坏规范化规则,这 修复了 文件系统中具体的记录。

    移动单个节点需要树的整个受影响部分 re-written。 Date、Darwen 和 Celko 类型的挚爱。

    MS HIERARCHYID 数据类型做同样的事情。给你大量的混凝土,每次节点变化时,都必须 jack-hammered 并再次浇筑。

好吧,没那么短。

对更新 2 的响应

对更新 3 的响应

对更新 4 的响应

对于每个吃食物的类别,您应该添加一个 table。例如,如果某种食物可能被某些特定性别食用,您将:

  Food_Gender(FoodID,GenderID)

对于人类,您将拥有:

 Food_Human(FoodID,HumanID)

动物种类:

 Food_AnimalSpc(FoodID,Species)

整个table:

Food_Table(FoodID,TableID)

其他类别依此类推