我有三张桌子:
Users: Depts Default
| fid | uid | rights | | fid | did | rights | | fid | rights |
|-----+-----+--------| |-----+-----+--------| |-----+--------|
| 1 | 1 | 4 | | 1 | 10 | 2 | | 1 | 2 |
| 3 | 1 | 4 | | 2 | 10 | 2 | | 2 | 4 |
+--------------------+ +--------------------+ +--------------+
这些用户根据用户ID及其所属部门定义用户对系统中文件的访问权限。访问文件时,默认权限(如果有)按顺序确定有效权限,这些权限由部门权限(如果有)覆盖,而这些权利又被用户权限(如果有)覆盖。
因此,在该示例中,用户1(部门10的成员)没有文件2的用户权限,但是从他的部门获得权限级别2。 (默认权利4不适用,因为他们被部门权利覆盖)
我需要查询此表结构以确定用户对一个或多个文件的有效权限。最初,我唯一的要求是一次获得一个文件的有效权限,我通过为三个子查询中的每一个分配优先级,按优先级顺序将它们与UNION
组合,然后只采用第一个结果,像这样:
select a.rights from
(select 100 as priority, rights from `Users` where `uid`=1 and `fid` = 2 union
select 200 as priority, rights from `Depts` where `did`=10 and `fid` = 2 union
select 300 as priority, rights from `Default` where `fid` = 2
) as a
order by priority asc limit 1;
现在,这可能不是特别有效,但到目前为止已经服务了。
我现在的问题是扩展此功能以检索用户对多个文件的有效权限。由于优先级结构,现在的查询无法完成。
我应该可以在三个表中使用FULL OUTER JOIN
来生成一组权限值COALESCE
,但MySQL不支持FULL OUTER JOIN
在Stack Overflow和其他地方进行了一些挖掘后,我到达了这里(UID,部门ID和文件ID仅供说明):
select u.fid as fid, u.rights as urights, d.rights as drights, def.rights as defRights
from
(users as u
left outer join Depts as d using (fid)
left outer join Default as def using (fid))
where fid in (21, 1823, 1830) and dept_id=10 and uid=1
union
select u.fid as fid, u.rights as urights, d.rights as drights, def.rights as defRights
from
(Depts as d
left outer join Users as u using (fid)
left outer join Default as def using (fid))
where fid in (21, 1823, 1830) and dept_id=10 and uid=1
union
select u.fid as fid, u.rights as urights, d.rights as drights, def.rights as defRights
from
(Default as def
left outer join Users as u using (fid)
left outer join Depts as d using (fid))
where fid in (21, 1823, 1830) and dept_id=10 and uid=1
从表面上看,这似乎有效,但使用WHERE
子句会错误地过滤结果。从我的阅读中看来,似乎使用ON
子句可能是解决方案,但是正确地使用语法已经打败了我。
对于我们上面的文件#2的例子,我应该得到
| fid | Users | Depts | Default |
+-----+-------+-------+---------+
| 2 | null | 2 | 4 |
+-----+-------+-------+---------+
当三个权利值合并时,这应该赋予2的有效权利。
此查询可能适用于此简单示例。测试中出现的问题是应该包含的一些文件不是。
所以,我的问题是:
如何使用ON
子句代替WHERE
编写查询?
作为奖励,是否有更好的方法来实现相同的结果?
作为一个脚注:整个结构需要及时审查,但现在不是时候了。这是我必须要处理的,直到后来的一些开发提示我们更好地实现更好的东西。
答案 0 :(得分:2)
您可以通过将它们组合在一起而不是使用where in
来创建您感兴趣的所有文件的内嵌视图。这将维护查询链的outer
nish
例如:
select files.fid, u.rights, d.rights, def.rights
from (
select 1 as fid
union all
select 2 as fid
union all
select 3 as fid
-- all the files you are interested in
) files
left join users u
on files.fid = u.fid
and u.uid = 2 -- put the user you are searching for here
left join depts d
on files.fid = d.fid
and d.did = 10 -- put the dept you are searching for here
left join `default` def
on files.fid = def.fid