使用 Junction & 标准化外键查找表
最近,我一直在摸索数据库规范化与连接表和查找表方面的外键之间的关系。
我目前有以下表格:Users、UserTypes、Roles、UsersInRoles 和 Permissions。 UserTypes 只是一个查找表,通过 Users 表中的外键提供类型名称和描述。角色是具有通过 UsersInRoles 表链接到每个用户的关联权限的各种角色。
我需要提出一个结构,允许我为每个用户提供多个角色,此外还为每个用户提供其所属的固定角色中可能未涵盖的特殊权限。
我有一个来自 Users 表的 UsersInRoles 表的外键,但认为它没有意义。相反,使用 Users 表到 UserTypes 表的外键似乎非常有意义。这是经验法则吗?连接表具有链接到其连接的表的主键的外键,而主表具有链接到关联查找表的主键的外键?
参数:
- 每个用户可以拥有一个或多个角色
- 每个角色都有一组固定的权限
- 每个用户可以拥有其角色未提供的附加权限
我怀疑我可能还需要一个 PermissionsInRoles 连接表以及一个对于用户权限?但这太荒谬了不是吗?一定有更好的方法。我完全相信我在这里失去了理智,哈哈。任何帮助将不胜感激。这让我头晕目眩:P
更新
这基本上是如何设置的吗?我可能会删除 UsersInRoles 表,以便每个用户只能担任一个角色,并且可以通过 SpecialPermissions 连接表添加其他权限。从用户界面的角度来看,我认为在向用户分配权限时可能会很好,选择“角色”只需选中与该角色关联的相应框,然后进行自定义并提交。这样我想我可能只需要用户和权限表之间的连接表?啊。这对于第一次数据库设计者来说是相当令人畏惧的哈哈。还记得你刚开始创业的时候吗?或者也许你们比我更有天才,哈哈。
架构图像链接(尚无法发布图像)
这是一篇简洁的学术文章(尽管已经有 10 岁了)关于查询驱动的数据库设计,标题为:“针对多种查询模式的稳健数据库设计”。结论部分有一个有趣的方法。
I've been scratching my head lately over the relationship between database normalization and foreign keys with respect to junction tables and lookup tables.
I’ve currently have the following tables: Users, UserTypes, Roles, UsersInRoles, and Permissions. UserTypes is simply a lookup table providing the name of the type, with description, via a foreign key in the Users table. Roles are the various roles with associated Permissions linked to each User via the UsersInRoles table.
I need to come up with a structure that allows me to provide multiple Roles for each User, in addition to special permissions for each respective User that may not be covered in the fixed Roles of which they are a member.
I had a foreign key to my UsersInRoles table from the Users table, but decided that it just didn’t make sense. Conversely, it seems to make perfect sense to use a foreign key from the Users table to the UserTypes table. Is this the rule of thumb? That junction tables have foreign keys linking to the primary keys of the tables it joins, while master tables have foreign keys linking to the primary key of associated lookup tables?
Parameters:
- Each User can have one or multiple Roles
- Each Role has a fixed set of Permissions
- Each User can have additional Permissions not provided by their Roles
I suspect I may also need a PermissionsInRoles junction table as well as one for PermissionsInUsers? But this is just ridiculous isn't it? There just must be a better way. I'm thoroughly convinced that I'm losing my mind here, lol. Any help would be greatly appreciated. This has got my head spinning :P
UPDATE
Is this basically how it would be setup? I might get rid of the UsersInRoles table so each user can only be in one role, and additional permissions can be added via the SpecialPermissions junction table. From a UI standpoint, I was thinking it might be good when assigning permissions to a user, selecting a "Role" would simply check the appropriate boxes associated with that role, then you customize that and submit. That way I think I would only need a junction table between the Users and Permissions tables perhaps? Ugh. This is quite daunting for a first time database designer haha. Remember when you were just starting out? Or maybe you guys are more of a genius than I am, lol.
Schema Image link (can't post images yet)
Here's a neat scholarly article (albeit 10 years old) on query-driven database design titled: "Robust Database Design for Diverse Query Patterns". The Conclusion section has an interesting approach.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
好吧,您已经说过其中一个要求是“每个角色都有一组固定的权限”。因此,为了满足该要求,您需要存储适用于每个角色的权限。
您不需要两个不同的表来实现该要求。
出于同样的原因,您已经说过“每个用户都可以拥有其角色未提供的附加权限”。为了满足该要求,您必须存储用户特定的权限。
因此,再次强调,您不需要两个不同的表来实现该要求。这两个表都采用 5NF。
有什么可笑的呢?
如果您需要有关实际表的具体建议,请编辑您的问题并为表插入 DDL。
后来
我看了你的图表。并非每张桌子都需要 ID 号; id 数字与标准化无关。
如果我正在设计您的系统,我可能不会在 Roles、Permissions 和 UserTypes 表中使用 id 编号,直到我发现 id 编号可以修复的性能问题。 (在过去 30 年的大多数系统中,这意味着,几乎从来没有。)在使用 ID 号之前,我还会考虑并测试使用人类可读的代码。人类可读的代码通常不需要连接; id 号始终需要连接。
在大多数 SQL dbms 中,您可以在
CREATE DOMAIN
语句中组合数据类型和检查约束。在 PostgreSQL 中,您可以使用类似的方法来减少表的数量。其次,
当行数稳定且相对较小时,使用 CREATE DOMAIN 语句替换表最为有用。就我个人而言,我更喜欢有桌子。
如果您坚持使用 ID 号,则还需要对 Roles.RoleName、Permissions.Description 和 UserTypes.UserType 进行 UNIQUE 约束。
否则,你似乎做得很好。
Well, you already said one of the requirements was "Each Role has a fixed set of Permissions". So to fulfill that requirement, you need to store permissions that apply to each role.
You don't need two different tables to implement that requirement.
By the same token, you've already said "Each User can have additional Permissions not provided by their Roles". To fulfill that requirement, you have to store user-specific permissions.
So, again, you don't need two different tables to implement that requirement. Both those tables are in 5NF.
What's ridiculous?
If you want specific advice about your actual tables, edit your question and insert DDL for your tables.
Later
I looked at your diagram. Not every table needs an id number; id numbers have nothing to do with normalization.
If I were designing your system, I probably wouldn't use id numbers in the tables Roles, Permissions, and UserTypes until I saw a performance problem that id numbers could fix. (In most systems over the last 30 years, that means, well, almost never.) Before I used an id number, I'd also consider and test using a human-readable code instead. Human-readable codes often don't require joins; id numbers always require joins.
In most SQL dbms, you can combine a data type and check constraint in a
CREATE DOMAIN
statement. In PostgreSQL, you might use something like this to reduce the number of tables.Followed by
Replacing a table with a
CREATE DOMAIN
statement is most useful when the number of rows is stable and relatively small. Personally, I'd rather have the tables.If you stick with id numbers, you also need UNIQUE constraints on Roles.RoleName, Permissions.Description, and UserTypes.UserType.
Otherwise, you seem to be doing fine.
如果您的安全对象只是一个产品表(或一组表),并且您正在使用 SSMS (SQL-Server Management Studio),那么您不应该从头开始发明自己的安全模式。
我建议您在 SSMS 中设置用户和角色 - 展开数据库,然后 ->安全性-->用户等。右键单击用户,查找安全对象,然后您可以将用户分配给角色,也可以直接分配对象(表等)。或者右键单击角色,您会看到类似的选项。无论你做什么,如果可以的话,都不要创建自己的安全模式。
如果您需要您的网络应用程序能够访问数据库,请查看“实用程序帐户”(这些帐户就像用户,在服务器级别而不是数据库级别创建,但您可以从那里将它们带入数据库。) ;或者,如果您能够在用户登录数据库时从您的内部网络传递用户的信用信息,请考虑模拟。可以将实用程序帐户或用户分配给角色,或者在没有角色的情况下授予对数据库对象的直接访问权限 - 无论您需要什么。
If your securables are just a products table (or set of tables), and you're using SSMS (SQL-Server Management Studio) then you should not be inventing your own security schema from scratch.
What I would recommend is that you setup your users and roles in SSMS -- expand the Database, then --> Security --> Users, etc. Right-click a user, look for securables, and then you can assign the user to roles, or also, just objects (tables, etc.) directly. Or right-click roles and you have similar options. Whatever you do, stay away from creating your own security schema, if you can help it.
If you need your web app to have access to the database, then look into "utility accounts" (these are like users, created at the server level instead of the database level, but then you can bring them into your database from there.); or look into impersonation if you're able to pass users' creds from your internal network when they login to the database. Utility accounts or users can be assigned to roles, or granted direct access to database objects without roles -- whatever you need.
我之前在类似的场景中做过一件事:
将角色和用户保留在同一个表中。
有一个对象表(您将授予权限的表/查询/表单/等)
有一个权限表 - 这是您将角色/用户链接到对象的地方(即,John 可以在表 1 上进行 SELECT)
最后,有一个继承表 - 这是您将角色/用户相互链接的地方(即,John 有权执行 Role1 可以执行的任何操作)
例如 - 像这样的结构:
例如:
那么如果您想查询, “约翰能做什么?”,你会做这样的事情:
这个实现效果很好。如果您想查看类似的实现,请查看 SQL-Server 的实现(或者更好的是,使用它,而不是从头开始重新创建轮子。)
One thing I've done before, in a similar-sounding scenario:
Keep Roles and users in the same table.
Have an objects table (the tables/queries/forms/etc. you will be granting permissions to)
Have a permission table -- this is where you will link roles/users to objects (i.e., John can SELECT on table 1)
Finally, have an Inheritance table -- this is where you will link roles/users to each other (i.e., John has permission to do whatever Role1 can do)
For example -- a structure like this:
For example:
So then if you wanted to query, "What can John do?", you'd do something like this:
This implementation works well. If you want to see a similar implementation, look at SQL-Server's implementation (or better yet, USE it, instead of re-creating the wheel from scratch.)