使用Junction和&amp ;;标准化外键查找表

时间:2011-07-11 22:41:37

标签: database foreign-keys normalization lookup junction

最近,关于联结表和查找表,数据库规范化和外键之间的关系让我感到头疼。

我目前有以下表:Users,UserTypes,Roles,UsersInRoles和Permissions。 UserTypes只是一个查找表,通过Users表中的外键提供类型名称和描述。角色是通过UsersInRoles表链接到每个用户的关联权限的各种角色。

我需要提出一个允许我为每个用户提供多个角色的结构,以及每个用户的特殊权限,这些权限可能不在他们的固定角色中是会员。

我从Users表中获取了UsersInRoles表的外键,但认为它没有意义。相反,使用Users表中的外键到UserTypes表似乎是完全合理的。这是经验法则吗?连接表有外键链接到它连接的表的主键,而主表有外键链接到相关查找表的主键吗?

参数:

  • 每个用户可以拥有一个或多个角色
  • 每个角色都有一组固定的权限
  • 每个用户都可以拥有其角色未提供的其他权限

我怀疑我可能还需要一个PermissionsInRoles联结表以及一个PermissionsInUsers?但这只是荒谬不是吗?必须有一个更好的方法。我完全相信我在这里失去了理智,哈哈。任何帮助将不胜感激。这让我头晕目眩:P

更新
这基本上是如何设置的?我可能会删除UsersInRoles表,因此每个用户只能在一个角色中,并且可以通过SpecialPermissions联结表添加其他权限。从UI的角度来看,我认为在为用户分配权限时可能会很好,选择“角色”只需检查与该角色关联的相应框,然后自定义并提交。那样我认为我只需要用户和权限表之间的联结表?啊。对于第一次数据库设计师来说,这是非常令人生畏的哈哈。还记得你刚开始的时候吗?或许也许你们比我更天才,哈哈。

Schema Image link(无法发布图片)

这是一篇题为“Robust Database Design for Diverse Query Patterns”的查询驱动数据库设计的一篇简洁的学术文章(尽管已有10年历史)。结论部分有一个有趣的方法。

3 个答案:

答案 0 :(得分:1)

  

我怀疑我可能还需要一个PermissionsInRoles联结表   作为PermissionsInUsers的一个?

嗯,您已经说过其中一个要求是“每个角色都有一组固定的权限”。因此,要满足该要求,您需要存储适用于每个角色的权限。

Table: role_permissions
PK:    (Role, Permission)

Role    Permission
--
User    Create
User    Update
Admin   Create
Admin   Update
Admin   Delete

您不需要两个不同的表来实现该要求。

出于同样的原因,您已经说过“每个用户都可以拥有其角色无法提供的额外权限”。要满足该要求,您必须存储特定于用户的权限。

Table: user_permissions
PK:    (username, permission)

username    permission
--
user1       Rename
user1       Leak to News of the World
user2       Randomly corrupt data

因此,再次,您不需要两个不同的表来实现该要求。这两个表都是5NF。

  

但这只是荒谬不是吗?

有什么荒谬的?

  • 您对权限有非常详细的要求吗?
  • 您是否在表格中存储业务数据(如权限)?
  • 需要多个表来建模您的权限要求?
  • 别的什么?

如果您需要有关实际表格的具体建议,请编辑您的问题并为表格插入DDL。


<强>后来

我查看了你的图表。并非每个表都需要一个id号码; id号与规范化无关。

如果我正在设计你的系统,我可能不会在表Roles,Permissions和UserTypes中使用id号,直到我看到id号可以解决的性能问题。 (在过去30年的大多数系统中,这意味着,几乎从不。)在我使用id号之前,我还要考虑并使用人类可读的代码进行测试。人类可读的代码通常不需要连接; id号总是需要连接。

在大多数SQL dbms中,您可以在CREATE DOMAIN语句中组合数据类型和检查约束。在PostgreSQL中,您可以使用类似的东西来减少表的数量。

CREATE DOMAIN role AS VARCHAR(7) NOT NULL
  CHECK (VALUE in ('Admin', 'User', 'Guest'));

其次是

CREATE TABLE user_roles (
  user_id integer not null references users (id),
  role_name role 
);

当行数稳定且相对较小时,用CREATE DOMAIN语句替换表是最有用的。就个人而言,我宁愿拥有桌子。

如果你坚持使用id号,你还需要对Roles.RoleName,Permissions.Description和UserTypes.UserType的UNIQUE约束。

否则,你似乎做得很好。

答案 1 :(得分:0)

我之前做过的一件事,就是在一个类似的场景中:

将角色和用户放在同一个表格中。

有一个对象表(表/查询/表单等等,你将授予权限)

拥有权限表 - 这是您将角色/用户链接到对象的位置(即John可以在表1中选择)

最后,有一个继承表 - 这是你将角色/用户相互链接的地方(即John有权做任何Role1可以做的事情)

例如 - 像这样的结构:

例如:

Users Table:
UserID -- User -- UserTypeID
1 ------- John Smith --- 1
2 ------- Sally Fort --- 1
3 ------- Public Role -- 2
4 ------- Special Role - 2

UserType Table:
UserTypeID -- Description
1 ----------- Human Being
2 ----------- Role

Objects Table:
1 -- Data-Entry Form 1
2 -- Data-Entry Form 2
3 -- Query 1
4 -- Table 1

Permissions Table
UserID -- ObjectID -- Permission
1      -- 1        -- Update (This says John can Update Data-Entry Form 1 (via direct permission))
3      -- 1        -- Update (This says that the Public Role can Update Data-Entry Form 1)
3      -- 2        -- Update (...as well as Data-Entry Form 2)
4      -- 3        -- Select (This says that the special role can Select from Query1)
4      -- 4        -- Insert (...the special role can Insert into Table1)

Permission Inheritance Table
UserID -- UserID_ToInheritFrom
1      -- 3 (this says John can do whatever the Public Role can do)
1      -- 4 (this says John can do whatever the Special Role can do)
2      -- 3 (this says Sally can do whatever the Public Role can do)

那么如果你想查询“John能做什么?”,你会做这样的事情:

SELECT
   ObjectID,
   Permission
FROM
   PermissionsTable
WHERE
   UserID = 1 -- John has direct permission
   OR UserID IN (SELECT UserID_ToInheritFrom FROM PermissionInheritanceTable WHERE UserID = 1)
   -- John has indirect permission via the Permission Inheritance Table (or you can call it the "role
   -- membership table" if that's easier for you to think of that way.)

此实施效果很好。如果你想看到类似的实现,请查看SQL-Server的实现(或者更好的是,使用它,而不是从头开始重新创建轮子。)

答案 2 :(得分:0)

如果您的securables只是一个产品表(或一组表),并且您正在使用SSMS(SQL-Server Management Studio),那么您不应该从头开始创建自己的安全架构。

我建议您在SSMS中设置用户和角色 - 展开数据库,然后 - &gt;安全 - &gt;用户等。右键单击用户,查找安全性,然后您可以将用户直接分配给角色,或者只分配对象(表等)。或者右键单击角色,您也有类似的选项。无论您做什么,如果可以提供帮助,请远离创建自己的安全架构。

如果您需要Web应用程序可以访问数据库,那么请查看“实用程序帐户”(这些用户是在服务器级别而不是数据库级别创建的,但是您可以将它们从那里。);如果您在登录数据库时能够从内部网络传递用户的信用,请查看模拟。可以将实用程序帐户或用户分配给角色,或者授予对没有角色的数据库对象的直接访问权限 - 无论您需要什么。