多对多与"主要"
我正在处理一个需要代表计算机及其用户的数据库。每台计算机可以有多个用户,并且每个用户可以与多台计算机关联,因此这是经典的多对多关系。但是,还需要有一个"主要"用户的概念。我必须能够与主要用户一起加入,以列出所有具有主要用户的计算机。我不确定在数据库中构造此结构的最佳方法是什么:
1)正如我目前正在做的那样:将表与一个布尔IsPrimary列链接。加入需要类似ON(c.computer_id = l.computer_id AND l.is_primary = 1)之类的东西。它可以工作,但是感觉不对,因为将数据限制为每台计算机只有一个主要用户并不容易。
2)计算机表上的一个字段直接指向用户行,该用户表中的所有行均表示非主要用户。这更好地表示了每台计算机一个主节点的约束,但是使获取计算机用户列表变得更加困难。
3)计算机表上的字段链接到链接表中的一行。感到奇怪...
4)还有别的吗?
描述这种关系的"关系"方式是什么?
编辑:
@Mark Brackett:第三种选择对我来说似乎并不陌生,因为我们已经展示了它的外观。由于某种原因,我什至没有考虑使用复合外键,因此我想必须在链接表上添加一个Identity列才能使其正常工作。看起来很棒,谢谢!
@ j04t:太好了,很高兴我们现在就#3达成共识。
解决方案
由于主要用户是计算机和用户的功能,因此我倾向于采用让primaryUser作为链接表中的列的方法。
我可以想到的另一种选择是直接在计算机表本身上具有primaryUser列。
我本来要在另一个表PRIMARY_USERS上将其在computer_id上具有唯一性,并同时将用户的computer_id和user_id用作外键。
解决方案1或者2都可以使用。在这一点上,我想问自己,哪一个将更容易使用。尽管通常会在链接表上使用一个标志,然后在computer_id和isPrimaryUser上强制使用唯一约束,但我已在不同情况下使用了这两种方法,这样可以确保每台计算机只有一个主要用户。
2对我来说很合适,但是我将测试1、2和3的性能,这些性能通常用于我们通常执行的查询以及具有的数据量。
作为一般经验法则,我倾向于认为,在有多种实现方式的地方,我们应该查看查询需求并设计模式,以便在最常见的情况下获得最佳的性能和资源利用率。
在罕见的情况下,如果我们遇到同样常见的情况却提出相反的实现,请使用Occam的剃刀。
编辑 -
最初的3次我都没有正确地考虑它。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
我投赞成票-
(3号解决方案)
用户数
user id (pk)
电脑
computer id (pk) primary user id (fk -> computer users id)
电脑使用者
user id (pk) (fk -> user id) computer id (pk) (fk -> user id)
这是我能想到的最佳解决方案。
为什么我喜欢这种设计。
1)因为这是涉及计算机和用户的关系,所以我喜欢能够将一个用户作为主要用户关联到多台计算机的想法。但是,在使用此数据库的地方可能永远不会发生这种情况。
2)我不喜欢在链接表上使用primary_user的原因
(computer_users.primary_user_id fk-> users.user_id)
是为了防止一台计算机拥有多个主要用户。
鉴于这些原因,第3种解决方案看起来更好,因为我们将永远不会遇到其他方法所遇到的一些可能的问题。
解决方案1问题每台计算机可能有多个主要用户。
解决方案2问题当计算机和用户彼此不链接时,计算机链接到主要用户。
computer.primaryUser = user.user_id computer_users.user_id != user.user_id
解决方案3问题看起来有点奇怪,不是吗?除此之外,我什么都没想到。
解决方案4问题我想不出其他任何方法。
这是第四次编辑,所以我希望它仍然有意义。
在我处理的应用程序中,我们遇到的情况与此类似。在该应用程序中,我们的帐户可以添加许多客户,但主要客户只能是一个。
我们使用链接表(如我们所愿),但在链接表上有一个Sequence值。主要用户是Sequence = 1的用户。然后,我们在该链接表上有一个AccountID和Sequence的索引,以确保AccountID和Sequence的组合是唯一的(从而确保在一个客户中,没有两个客户可以是主要客户)。帐户)。因此,我们将拥有:
LEFT JOIN c.computer_id = l.computer_id AND l.sequence = 1
选项3尽管可能会感到很奇怪,但它与我们要建模的对象最接近。我们将执行以下操作:
User { UserId PRIMARY KEY (UserId) } Computer { ComputerId, PrimaryUserId PRIMARY KEY (UserId) FOREIGN KEY (ComputerId, PrimaryUserId) REFERENCES Computer_User (ComputerId, UserId) } Computer_User { ComputerId, UserId PRIMARY KEY (ComputerId, UserId) FOREIGN KEY (ComputerId) REFERENCES Computer (ComputerId) FOREIGN KEY (UserId) REFERENCES User (UserId) }
这将为我们提供0或者1个主用户(如果需要,PrimaryUserId可以为空),该主用户必须位于Computer_User中。编辑:如果用户只能是一台计算机的主要用户,则Computer.PrimaryUserId上的UNIQUE CONSTRAINT将强制执行该操作。请注意,不要求所有用户都必须是某台计算机上的主用户(这将是1:1关系,并且要求他们位于同一表中)。
编辑:一些查询向我们展示此设计的简单性
--All users of a computer SELECT User.* FROM User JOIN Computer_User ON User.UserId = Computer_User.UserId WHERE Computer_User.ComputerId = @computerId --Primary user of a computer SELECT User.* FROM User JOIN Computer ON User.UserId = Computer.PrimaryUserId WHERE Computer.ComputerId = @computerId --All computers a user has access to SELECT Computer.* FROM Computer JOIN Computer_User ON Computer.ComputerId = Computer_User.ComputerId WHERE Computer_User.UserId = @userId --Primary computer for a user SELECT Computer.* FROM Computer WHERE PrimaryUserId = @userId