数据库建模 - 多对多中的任何一个/或者

时间:2012-08-27 21:36:42

标签: sql sql-server-2008 database-design

在我想要建模的多对多关系中,我有一种或两种情况。

所以我有这些表:

Message
----
*MessageID
MessageText

Employee
----
*EmployeeID
EmployeeName

Team
----
*TeamID
TeamName

MessageTarget
----
MessageID
EmployeeID (nullable)
TeamID (nullable)

因此,Message可以包含Employee个列表,或Team个列表MessageTargetMessageTarget表是否具有实现此关系的最佳方式?我可以有效地对MessageTarget施加什么约束?我应该如何在MessageTarget表上创建主键?

有问题的数据库是SQL Server 2008

6 个答案:

答案 0 :(得分:2)

您提出此问题的方式似乎是Employee 是-a MessageTarget,而Team 似乎是 MessageTarget
因此,Message的{​​{1}}为TargetEmployee。 在我看来,这就像SQL中的继承(或组合)问题 看看“Implementing Table Inheritance in SQL Server”。 Team本身不是Employee,但也许这方面的读数可以帮助您进行建模

答案 1 :(得分:2)

所以你想确保单个消息的MessageTargets都设置了employeeID或teamID,但不是两者的混合?

根据您的RDBMS,您可以创建物化视图并对其进行约束。视图看起来像

select messageId, count(employeeId), count(teamId) from messageTarget

在此,你会设置一个检查约束,确保其中一个计数为零。

或者,您可以将MessageTarget替换为两个表:EmployeeMessageTarget和TeamMessageTarget,每个表只包含一个TargetId,第一个表中包含EmployeeId,第二个表中包含TeamId。

您的Message表将获得两个新字段:EmployeeMessageTargetId和TeamMessageTargetId以及一个检查约束,确保其中至少有一个为null。如果您使两个字段都是唯一的,则可以使用* MessageTarget表中的外键。

答案 2 :(得分:1)

你也可以考虑

MessageTarget
----
MessageID
targetID (not nullable)
targetType

然后将类型设置为它应该是...

答案 3 :(得分:1)

是 - 关系通常是gen-spec模式的实例。类表继承是为gen-spec案例设计表的一种方法。

http://martinfowler.com/eaaCatalog/classTableInheritance.html

答案 4 :(得分:1)

由于员工和团队无法混合使用相同的消息,因此您需要执行以下操作:

enter image description here

  • MessageEmployee.MessageIdForEmployee引用Message.MessageIdForEmployee
  • MessageTeam.MessageIdForTeam引用Message.MessageIdForTeam

Message表上有以下约束:

CHECK (
    (MessageIdForEmployee = MessageId AND MessageIdForTeam IS NULL)
    OR
    (MessageIdForEmployee IS NULL AND MessageIdForTeam = MessageId)
)

请注意我们如何为每种子表设置单独的联结表,并且联结表引用父亲的PK。而是每个联结表引用单独的 UNIQUE字段。由于这些字段中只有一个可以是非NULL,因此只能将一种子项连接到任何给定的消息。

注意:将MessageIdMessageIdForEmployeeMessageIdForTeam匹配并非绝对必要,但它可能会稍微简化查询。

答案 5 :(得分:0)

考虑删除MessageTarget实体中的“团队ID”字段,以便您只拥有messageId和employeeId。为了满足团队的需求(如果要求每个员工都必须是团队成员),您可以拥有另一个实体“团队消息”,其中数据库触发器将确保在插入该表时,您可以插入在团队中的每个员工的消息目标表中的行。这样,您可以方便地从每条消息链接回MessageTarget表中的员工或从“团队消息”表返回到团队。还可以在ORM框架中方便地访问,其中Employee实体只有一个List而团队也有相同的