【问题标题】:T-SQL Constraint on Foreign Key and one Condition外键和一个条件的 T-SQL 约束
【发布时间】:2015-01-23 13:57:30
【问题描述】:

我正在尝试建立一个小型数据库来组织权限。我正在使用这四个表:

  • User,列:用户 ID、名称
  • UserGroup,列:用户组ID、名称
  • UserGroupUsers,列:UserID、UserGroupID
  • Permission,列:PermissionID、UserID、UserType、Permission、PermissionValue

规则:

  • 一个用户可以在多个组中
  • 一个组可以有多个用户
  • 权限可以是用户的一部分,也可以是用户组的一部分。

现在我正在尝试设置一个约束,每当我删除 useruserGroup 时,我还想删除带有数据库约束的 Permission 行。

useruserGroup的关系如下:

User 的一行可以在Permissions 中包含多行,但需要附加条件:UserType = 1

各组相同:

UserGroup 的一行可以在Permissions 中包含多行,但有额外的条件UserType = 2

例子:

表:权限:

PermissionID   |   UserID   | UserType | Permission | PermissionValue
---------------------------------------------------------------------
1                  1          1          MainMenu      15
2                  1          2          MainMenu      2

第 1 行表示用户 ID = 1 的用户的用户权限

第 2 行表示 usergroupID = 1 的用户组的 userGroup 权限。

到目前为止我尝试了什么:

ALTER TABLE dbo.permissions 
  ADD CONSTRAINT fk_permissionsAccounts 
  FOREIGN KEY(userID) 
  REFERENCES dbo.users(userID) 
    ON UPDATE CASCADE 
    ON DELETE CASCADE 

但这实际上是错误的,因为它应该只发生在 UserType=1

接下来我尝试在UsersGroups 两个表中添加一列UserType,包括类型,但我得到了消息:

该字段不是键的一部分。

此尝试的来源:

ALTER TABLE dbo.permissions 
   ADD CONSTRAINT fk_permissionsAccounts 
   FOREIGN KEY(userID, accountType)
   REFERENCES dbo.users(userID, accountType) 
       ON UPDATE CASCADE 
       ON DELETE CASCADE 

我使用的是 SQL Server 2008

我很乐意提出任何建议。提前致谢。

编辑解决方案:

我已经编辑了表格:

Permission,列:PermissionID、UserID、UserGroupID、Permission、PermissionValue。

我在null-allowed 两个属性上都设置了:UserIDUserGroupID,但添加了一个检查约束,它只允许填写两个字段之一,其他字段必须为空:

ALTER TABLE dbo.permissions
WITH CHECK ADD  
CONSTRAINT chk_permissions
CHECK  (
       ([AccountID] IS NULL AND [AccountGroupID] IS NOT NULL) OR 
       ([AccountID] IS NOT NULL AND [AccountGroupID] IS NULL)
        )

现在我可以添加我的默认约束了:

ALTER TABLE dbo.permissions 
  ADD CONSTRAINT fk_permissionsUsers
  FOREIGN KEY(userID) 
  REFERENCES dbo.users(userID) 
    ON UPDATE CASCADE 
    ON DELETE CASCADE 

和:

ALTER TABLE dbo.permissions 
  ADD CONSTRAINT fk_permissionsUserGroups
  FOREIGN KEY(userGroupID) 
  REFERENCES dbo.usergroups(userGroupID) 
    ON UPDATE CASCADE 
    ON DELETE CASCADE 

【问题讨论】:

  • 所以如果UserType 为2,实际上UserID 意味着包含来自UserGroup 表的UserGroupID,而不是来自User 表的实际UserID?如果没有,我不确定我是否理解这个结构
  • 是的,正确的。我将在问题中添加一个示例。
  • 那么我强烈推荐 Rhys 提倡的两列方法,或者 a) 给它一个清楚地表明它是要么用户或组 ID 的名称,或者b) 给它一个严格中立的名称,它包含什么类型的 ID。

标签: sql sql-server tsql


【解决方案1】:

你能稍微改变一下桌子的设计吗?如果您将 UserGroupId 添加到 Permission 表,那么这将变得更加简单。不需要 UserType 列(当然,除非你想要它)。 Permission 表中的行将有一个一个UserId 一个UserGroupId,但不能同时有这两者(检查约束可以强制执行此操作)。

此外,正如@Damien_The_Unbeliever 所指出的,使用名为 UserId 的列来保存 UserId 或 UserGroupId 并不理想。如果必须这样做,请更改列的名称以防止混淆。

【讨论】:

  • 感谢您的建议,我将尝试通过检查约束来解决这个问题。但主要是数据库表设计是一个团队的决定,首先,(没有约束)这在某种程度上更容易理解。我会在星期一给出反馈。我真的很感激这一点。谢谢。
  • 我用这种方法试了一下,结果成功了。我已经编辑了这个问题。再次感谢。
猜你喜欢
  • 1970-01-01
  • 2011-02-25
  • 2011-01-01
  • 1970-01-01
  • 2017-06-17
  • 2013-01-30
  • 1970-01-01
  • 2019-08-06
  • 2021-07-22
相关资源
最近更新 更多