具有多个嵌套表的数据库设计

Posted

技术标签:

【中文标题】具有多个嵌套表的数据库设计【英文标题】:Database design with multiple nested tables 【发布时间】:2013-07-17 07:00:20 【问题描述】:

我有一个关于桌子设计的问题。我有一个解决方案,在我看来应该可行,但没有。

考虑有两个实体“主题”和“流程”,它们都具有某些属性。每个“主题”可能与多个“进程”相关联。根据选择的“流程”,存在不同数量的实体“流程-属性”。换句话说,当用户将“进程”与“主题”相关联时,他应该只能编辑专门链接到它的“属性”。

最终我希望用户能够做 3 件事:

    创建新的“进程”并指定与之相关的“属性” 列出某个“主题”的所有“进程”,即使没有链接到它的“属性” 将“流程”与“主题”相关联,并且只允许评估预定义的“属性”

所以表格设计应该是这样的:

tblSubject=SubjectID,... tblProcess=ProcessID,... tblProcessProperty=PropertyID,... tblRelationProcessProperty=RelationProcessPropertyID, ProcessID, PropertyID tblRelationSubjectProcessProperty=RelationID, RelationProcessPropertyID, SubjectID, PropertyValue

只要每个“进程”都有一个“属性”,这显然就可以工作。所以我的错误是没有直接将“主题”链接到“流程”,但我无法直接获得表格设计。

感谢任何帮助。

【问题讨论】:

你的意思是你不能把桌子设计直? 我构建表格的方式并没有为我提供所需的功能。它应该类似于:将“进程”分配给“主题”。如果“流程”具有“属性”,也将它们分配给“主题”。 【参考方案1】:

在我看来,您尝试实现一种 EAV(实体-属性-值)设计。

您的表看起来还可以,但这种设计本身就需要复杂的 SQL。

有不同的方法可以做到这一点,但根据你上面的故事,我会选择这样的方法。

   Subject --< Process --< RelationshipProcessProperty >-- Property

您的财产将如下所示:

    "Property"
    PK PropertyId
    Name

您的 RelationshipProcessProperty 可能如下所示:

    "RelationshiipProcessProperty"
    PK RelationshipProcessProperty
    FK Process
    FK Property
    Value

您的 SQL 会变得复杂。进行这样的“通用”设计意味着您要在同一个表中查找多个值。

    ; with Property1 as(
    SELECT
    proc.Id as ProcessId,
    prop.Name,
    rrp.Value
    FROM Subject s
    LEFT JOIN Process proc
    ON s.SubjectId = proc.SubjectId
    LEFT JOIN RelationshipProcessProperty rpp
    on proc.ProcessId = rpp.ProcessId
    LEFT JOIN Property prop
    on rpp.PropertyId = prop.PropertyId
    WHERE
    s.Name = "Subject1"
    AND
    proc.Name = "Process1"
    AND
    prop.Name = "Property1"
    )

    , Property2 as(
    SELECT
    proc.Id as ProcessId,
    prop.Name,
    rrp.Value
    FROM Subject s
    LEFT JOIN Process proc
    ON s.SubjectId = proc.SubjectId
    LEFT JOIN RelationshipProcessProperty rpp
    on proc.ProcessId = rpp.ProcessId
    LEFT JOIN Property prop
    on rpp.PropertyId = prop.PropertyId
    WHERE
    s.Name = "Subject1"
    AND
    proc.Name = "Process1"
    AND
    prop.Name = "Property2"
    )

    SELECT
    p1.Name,
    p1.Value,
    p2.Name,
    p2.Value
    FROM
    Property1 p1
    LEFT JOIN Property2 p2
    on p1.ProcessId = p2.ProcessId

您可以使用此方法获取同一进程的多个属性。

要为指定进程指定属性,您需要创建进程类型表:

    "ProcessType"
    PK ProcessType
    Type

这确实意味着您需要在进程表中添加一个外键,以将其链接到它的类型。然后,您可以使用定义所有可用类型的关系表将 ProcessType 表链接到 Property 表。

    "EligibleProcessProperties"
    PK EligibleprocessPropertiesId
    FK ProcessType
    Fk Property

然后要找出该进程类型的所有可用属性,您将有一个相对简单的查询

    SELECT
    p.Name
    FROM
    ProcessType pt
    LEFT JOIN EligibleProcessProperties epp
    on pt.ProcessTypeId = epp.ProcessTypeId
    LEFT JOIN Property p
    on epp.PropertyId = p.PropertyId
    WHERE
    pt.Type = "Type1"

认为这就是你要找的东西(尽管我可能完全不在意)。如果这是您正在寻找的内容,那么 here 有一个非常好的帖子,它提出了一些很好的观点。

另外,我几乎 100% 有更好的方法来做我的长 ';with' 查询 - 但这就是我所知道的。希望其他人可以提供更好的。关键是,通过这种设计,您需要以一种或另一种方式进行子查询。

【讨论】:

第一眼看起来很棒。我会试一试,然后回复你。非常感谢,看起来工作量很大 啊哈,别担心,我只是希望这是您正在寻找的东西,我没有让您走错路。如果您发现它有用,请给我投票 - 与工作中的一些同事竞争。 :)【参考方案2】:

如果您已经有了一个想法,想要在架构中存储什么,那么创建架构本身的一个好策略是:

    将您的需求绘制为 ER 图 (https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model) 将图表转换为 SQL 模式 如有必要,带入第三范式 (http://en.wikipedia.org/wiki/Database_normalization)

在您的情况下,在第 1 步中您应该有类似

 ______       ___________          _______     _____    ____________
| Subj. |____/ associated \_______| Proc. |___/ has \__| Proc.prop. |
|_______|    \____________/       |_______|   \_____/  |____________|

如果您有不同类型的流程,您可以考虑对流程实体进行专门化。如果你真的想为每个进程选择具体的进程属性,你可能应该使基数 m:n 的 has-关系。

在 ER 图中,即使您有其他关系,也无法进行有效性检查(您的第三项)。在 SQL 模式中,您可以使用检查约束来强制执行此操作,或者让应用程序在插入新进程之前处理有效性。

【讨论】:

实际上上传 E-R-图会更好。下次我会这样做,谢谢。看来我得编写一个解决方案了……

以上是关于具有多个嵌套表的数据库设计的主要内容,如果未能解决你的问题,请参考以下文章

用于搜索具有无限个位域的表的 SQL 设计方法

如何创建具有多个子行(嵌套表)的 jQuery 数据表?

在设计数据库时,存储多个真/假值的首选方式是啥?

基于角色的数据库设计。作为用户属性或角色特定表的角色

处理多个表的工作流

具有显式表的 Prisma 查询嵌套列表