0

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

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

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

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

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

  • tblSubject={主题 ID,...}
  • tblProcess={进程 ID,...}
  • tblProcessProperty={PropertyID,...}
  • tblRelationProcessProperty={RelationProcessPropertyID, ProcessID, PropertyID}
  • tblRelationSubjectProcessProperty={RelationID, RelationProcessPropertyID, SubjectID, PropertyValue}

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

任何帮助表示赞赏。

4

2 回答 2

1

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

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

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

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

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

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

于 2013-07-17T08:43:28.857 回答
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"

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

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

于 2013-07-17T13:25:22.200 回答