具有多个嵌套表的数据库设计
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-图会更好。下次我会这样做,谢谢。看来我得编写一个解决方案了……以上是关于具有多个嵌套表的数据库设计的主要内容,如果未能解决你的问题,请参考以下文章