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

时间:2013-07-17 07:00:21

标签: sql database database-design nested

我对表格设计有疑问。我有一个解决方案应该在我看来有效,但不是。

考虑具有两个实体“主题”和“过程”,两者都具有某些属性。每个“主题”可以与多个“过程”相关联。根据选择的“过程”,存在不同数量的实体“过程 - 属性”。换句话说,当用户将“过程”与“主题”相关联时,他应该只能编辑与其特定关联的“属性”。

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

  1. 创建新的“流程”并指定与其关联的“属性”
  2. 列出某个“主题”的所有“流程”,即使没有链接到“属性”
  3. 将“处理”与“主题”相关联,仅允许评估预定义的“属性”
  4. 所以表设计应该是这样的:

    • tblSubject = {SubjectID,...}
    • tblProcess = {的ProcessID,...}
    • tblProcessProperty = {物业ID,...}
    • tblRelationProcessProperty = {RelationProcessPropertyID,ProcessID,PropertyID}
    • tblRelationSubjectProcessProperty = {RelationID,RelationProcessPropertyID,SubjectID,PropertyValue}

    只要存在与每个“过程”相关联的“属性”,这显然有效。所以我的错误不是直接将“主题”链接到“过程”,而是我不能直接得到表格设计。

    感谢任何帮助。

2 个答案:

答案 0 :(得分:1)

如果您已经有了想法,想要存储在架构中的内容,那么创建架构的好策略是:

  1. 将您的需求绘制为ER图(https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model
  2. 将图表转换为SQL架构
  3. 如有必要,请加入第3范式(http://en.wikipedia.org/wiki/Database_normalization
  4. 在您的情况下,在步骤1中,您应该有类似

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

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

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

答案 1 :(得分:1)

在我看来,你试图实现一种EAV(Entity-Attribue-Value)设计。

你的表似乎没问题,但这种设计固有地需要复杂的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%有更好的方法来做我的长';''查询 - 但这就是我所知道的。希望其他人可以提供更好的。关键是,使用此设计,您以某种方式需要子查询。