我正在开发一个需要代表计算机及其用户的数据库。每台计算机可以有多个用户,每个用户可以与多台计算机相关联,因此这是一种典型的多对多关系。但是,还需要一个“主要”用户的概念。我必须能够加入主用户才能列出所有主要用户的计算机。我不确定数据库中最好的结构方式是什么:
1)正如我现在所做的那样:将表与布尔的IsPrimary列链接起来。加入需要像ON一样(c.computer_id = l.computer_id AND l.is_primary = 1)。它有效,但感觉不对,因为将数据限制为每台计算机只有一个主要用户并不容易。
2)计算机表上直接指向用户行的字段,用户表中的所有行表示非主要用户。这表示每个计算机的一次主要约束更好,但却使计算机用户列表变得更难。
3)计算机表上的一个字段,链接到链接表中的一行。感觉奇怪......
4)还有别的吗?
描述这种关系的'关系'方式是什么?
编辑: @Mark Brackett:第三种选择对我来说似乎不那么奇怪,因为你已经展示了它的外观。出于某种原因,我甚至没有想到使用复合外键,所以我想我必须在链接表上添加一个标识列才能使其正常工作。看起来很棒,谢谢!
@ j04t:很酷,我很高兴我们现在同意#3。
答案 0 :(得分:7)
选项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中。编辑:如果用户只能是1台计算机的主要用户,则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
答案 1 :(得分:1)
编辑 - 我通过前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问题 - 我想不出任何其他方式。
这是第4次编辑,所以我希望它仍然有意义。
答案 2 :(得分:0)
由于主要用户是计算机和用户的功能,因此我倾向于采用将primaryUser作为链接表上的列的方法。
我能想到的另一个选择是直接在计算机表本身上安装一个primaryUser列。
答案 3 :(得分:0)
我会在computer_id
上制作另一个表格PRIMARY_USERS,并且同时制作USERS的computer_id
和user_id
个外键。
答案 4 :(得分:0)
解决方案1或2都可以使用。在这一点上,我会问自己哪一个更容易合作。我在不同的情况下使用了这两种方法,虽然我通常会在链接表上使用一个标志,然后在computer_id和isPrimaryUser上强制使用一个唯一的约束,这样就可以确保每台计算机只有一个主用户。
答案 5 :(得分:0)
2对我来说是正确的,但我会测试1,2和3的性能,通常用于您通常执行的各种查询以及您拥有的各种数据量。
作为一般经验法则,我倾向于认为,在有实现选择的地方,您应该查看查询要求并设计架构,以便在最常见的情况下获得最佳性能和资源利用率。
在罕见的情况下,你有同样常见的情况建议相反的实施,然后使用奥卡姆的剃刀。
答案 6 :(得分:0)
我们在应用程序中遇到类似情况我们的帐户可以有多个客户连接,但只有一个应该是主要客户。
我们使用链接表(如您所示)但在链接表上有一个Sequence值。主用户是序列= 1的用户。然后,我们在该帐户ID和序列的链接表上有一个索引,以确保AccountID 和序列的组合是唯一的(从而确保没有两个客户可以是帐户中的主要帐户)。所以你会:
LEFT JOIN c.computer_id = l.computer_id AND l.sequence = 1