Member-Role 是 N:N 关系。
Member MemberRole Role
+----------+ +----------+ +----------+
| Id | | MemberId | | Id |
| ... | | RoleId | | Name |
+----------+ +----------+ +----------+
- 大约有 15,000 名成员,他们的角色数量不一且可能为零。
- 大约有 50 个角色。
在数据库之外,我有需要检查数据库的允许-拒绝列表。列表可能看起来像
+a -b +c +d
这表示:
- 如果有角色a,
- 允许
- 别的,
- 如果有角色b,
- 否定
- 别的,
- 如果有角色c,
- 允许
- 别的,
- 如果有角色d,
- 允许
- 别的,
- 否定
- 如果有角色d,
- 如果有角色c,
- 如果有角色b,
例如,具有角色a和d的人将被允许,而具有角色b和d的人将被禁止。
通过从末尾开始,对项应用并集 (∪) 对+
项应用差 (-),可以轻松地将列表转换为数学方程-
。
+a -b +c +d
⇒ ( ( ( ∅ ∪ d ) ∪ c ) - b ) ∪ a
任何尾随的拒绝 ( -
) 都可以忽略,因此我们知道第一个将始终是联合。
+a -b +c +d
⇒ ( ( d ∪ c ) - b ) ∪ a
由此,我可以构建以下查询:
SELECT `MemberId` FROM `MemberRole` WHERE `RoleId` = @d
UNION SELECT `MemberId` FROM `MemberRole` WHERE `RoleId` = @c
EXCEPT SELECT `MemberId` FROM `MemberRole` WHERE `RoleId` = @b
UNION SELECT `MemberId` FROM `MemberRole` WHERE `RoleId` = @a
由于 x - y = x ∩ y',我们还可以推导出
+a -b +c +d
⇒ ( ( d ∪ c ) ∩ b' ) ∪ a
由此,我可以构建以下查询:
SELECT `Id`
FROM `Member`
WHERE (
(
EXISTS ( SELECT * FROM `MemberRole` WHERE `MemberId` = `Member`.`Id` AND `RoleId` = @d )
OR
EXISTS ( SELECT * FROM `MemberRole` WHERE `MemberId` = `Member`.`Id` AND `RoleId` = @c )
)
AND
NOT EXISTS ( SELECT * FROM `MemberRole` WHERE `MemberId` = `Member`.`Id` AND `RoleId` = @b )
)
OR
EXISTS ( SELECT * FROM `MemberRole` WHERE `MemberId` = `Member`.`Id` AND `RoleId` = @a )
检查成员是否被允许的最佳方法是什么?(答案通常是肯定的。)会使用WITH
帮助吗?
请注意,允许-拒绝列表的项目可以是角色 ID(数字)或角色名称(不是数字)。