动态内容类型:一个 table 有很多列,还是一个 table 每个?

Dynamic content types: One table with many columns or one table for each?

我 运行 不时进入这个问题,我想知道最终最好的解决方案是什么。

示例:

这里以"dynamic forms"为例。您有一个表单编辑器,可以添加表单字段(输入)。每个表单字段转换为不同类型的数据:

存储每个 for 的 结构 的简单方法可能是这样的:

没关系。但真正的问题是:如果有人填写此动态表格,我们如何正确存储数据?

我看到了两个解决方案:

我想知道:是否有更好的/其他解决方案?应该考虑什么是更好的方法?我可以想象这样的事情会经常出现 - 也许还有我不知道的第三种选择?

请记住 "form editor" 示例只是一个 示例 。这个问题适用于许多其他事物:模板编辑器、设置编辑器等。我问的是 "general" 解决这个问题的方法,不是专门针对表单编辑器的;)

注意:我不会考虑使用额外的非关系数据库作为解决方案。我主要是想把数据放在一个地方,所以问题只关注(My)SQL。

can add form fields (inputs).

让我们记住关系模型用于表示 'structured information'。

如果您可以自由添加(某物),听起来您的信息是非结构化的。

这些表单域来自哪里?它们代表业务实体还是实体的属性?那你不是已经在业务的数据模型中有了这些吗? (在非常一般的意义上使用 'business'。)

But the real question is: How do we properly store the data, ...

不,真正的问题是:我们如何正确地 retrieve/query 数据?数据代表什么?商业用户会问什么问题?

如果您还没有为业务建模entities/attributes,那么您将不知道如何甚至是否可以回答用户的问题。

因此,如果用户只是想随机 facts/fields 访问数据库并期望随机询问有关它的问题,则您没有结构化数据,并且关系数据库不是正确的工具工作。这听起来更像是 NoSQL 或某种 document/tagged/XML/JSON 数据库。 (尽管我怀疑 "database" 是否是这些的正确术语。)

I'm asking about a "general" approach with this problem, not specifically for form editors

This thing keeps popping up again and again and everyone I know seems to have a different take on it - but none of them has a really "proper" solution

在关系需求之后,当然是最高阶指令,我将采用通用方法正确解决方案作为over-arching 指令。

1 关系提升

但首先,更正。为了将数据模型提升到 Relational,没有它 straight-forward 解决方案将非常复杂(这正是 [a] 有这么多不正确方法的原因,并且[b] none 个是正确的解决方案)。

作为“关系”进行推广和营销的大部分“文学”和教科书实际上是 anti-relational。带有关系标签的 1970 年前记录归档系统,这显然是许多作者和“理论家”所能理解的全部。这种 pre-relational 文件系统与 关系模型 的主要区别在于,引用是逻辑的,而不是物理的。

  • 而在 pre-relational 系统中,物理 记录通过物理指针关联,例如 ID (INTEGER; GUID; UUID; etc),在关系范式中,逻辑 行(不是记录)由关系键关联。
  • Relational Key需要由数据组成,是逻辑的,不是物理的(物理指针不是数据)。

记录 ID 在关系数据库中没有用处。他们的目的是传播“理论家”的理解:

  • 让你迷惑
  • 保持 1970 年前的状态,pre-relational,身体心态
  • 从而防止关系思维和数据库

至少,每个这样的 Record ID 将是一个 additional 列和一个 additional 索引。

  • Additional,不是,而是,因为逻辑数据(Keys)上的索引是数据完整性所必需的,否则你会有重复且不完整。

因此,您的要求提升为关系型,每列少一列和索引table:

备注

2 个必需的关系键

第二个需要了解的是关系键的完整性特征,您不会拥有它,因为“理论家”很幸运地没有意识到它。这是与问题相关的解释,而不是完整的教程。假设您确实需要数据完整性和关系完整性( 关系模型 提供的逻辑特征(与引用完整性不同,后者是由 SQL 提供的物理设施)。我们将需要它,以便控制(提供完整性)数据层次结构中所需的数据结构 'lower',用于“存储”。

  • 虽然上述[1]对于那个目的是正确的,但我们还有一个额外的要求:我们需要FieldType in FormField.PK 这样它就可以迁移到它的 child tables.
  • 但是当然,我们一定不能从[1]上面的逻辑FormField.PK中减去。如果我们这样做,它将失去其完整性和意义。
  • 所以我们:
    • 添加所需的关系键 [2]
    • 使它成为主键因为那是被迁移的
    • 我们通过将其设为 备用键
    • 来维护原始主键 [1]
    • 将关系 FieldType::FormFieldNon-Identifying 更改为 Identifying.

3 关系解决方案 • 子类型

现在解决方案很简单。

I see two solutions to this [A] or [B]

肯定是 [B],通过一些改进使其达到标准。

[A] 是一个没有完整性的非规范化混乱,这将是维护的噩梦。 Null 是非常有问题的,外键中的 Null 是自杀。

but [B] will require a lot more complexity when storing and fetching data, since the program has to know the type, use the right table, etc etc.

存储空间

完全没有。

  • 耐心等待,解决方案如下
  • 您清楚地了解数据(“存储”)table必须键入(或强制转换)
  • 它需要一个普通的Exclusive Subtype结构。 (自 1960 年代以来,我们在 DBMS 中就有了子类型。)
  • 我已经在 Basetype 中提供了输入(转换)控件
    • 首先,通过在parent FormField主键中插入FieldType,这样它就会被迁移
    • 其次,通过使用Non-Identifying关系,使其不在childUserField
    • 的Key中
    • 但它仍然是 non-key 列,并且它可用作 Basetyp 的 Discriminator
  • 现在,可以理解为什么 [1][ 和 [2] 必须先实施了
  • 看看您是否能欣赏关系键提供的关系完整性(与参照完整性不同):
    • UserField是存在于FormName
    • 中的CONSTRAINEDFieldNames
    • 逻辑数据完整性级别,这是关系数据库中的标准票价,在“理论家”以欺诈方式销售的 pre-relational 物理(Record ID 基础)归档系统中无法实现关系
  • Subtype Exposition 初学者

此外,您应该使用 ACID 事务(自第一个版本以来 SQL 合规性的要求),而不是直接从程序中使用 INSERT/UPDATE/DELETE。这将简化应用程序和程序代码,并消除其他数以千计的错误。如果按照 OLTP 标准实施,它可以最大限度地减少锁定和争用,并减少(如果不能消除)死锁。

检索

不是真的。可能不简单,绝对不复杂,但就是straight-forward.

  • 使用VIEW(这是VIEWS的经典用法)
    • 用于检索已知子类型:
      每个子类型一个视图
    • 用于检索未知子类型:
      任何子类型的一个视图(带有UNION)(这将return每个基本类型只有一个,无论它是哪个子类型)
      (这不是“超类型”,anti-relational 深受“理论家”喜爱的概念,天哪。)
  • 这将使 SQL 编码也 straight-forward。

再来一个