左外连接、WHERE 子句和 COALESCE
Left Outer Joins, WHERE clause and COALESCE
我有三个table:
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 不适用,因为它们已被部门权限覆盖)
我需要查询这个table结构以确定用户对一个或多个文件的有效权限。最初,我唯一的要求是一次获得一个文件的有效权限,我通过为三个子查询中的每一个分配优先级,按优先级顺序将它们与 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;
现在,这可能不是特别有效,但到目前为止它已经起作用了。
我现在的问题是扩展它以检索用户对多个文件的有效权限。由于优先级结构,现有查询无法做到这一点。
我应该能够在三个 table 中使用 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
来编写查询?
作为奖励,是否有更好的方法来达到相同的结果?
作为脚注:整个结构需要及时审查,但那个时间不是现在。这是我必须使用的,直到后来的一些开发提示我们实现更好的东西。
您可以通过将所有您感兴趣的文件合并在一起来创建一个内联视图,而不是使用 where in
。这将维护查询链的outer
结尾
例如:
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
我有三个table:
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 不适用,因为它们已被部门权限覆盖)
我需要查询这个table结构以确定用户对一个或多个文件的有效权限。最初,我唯一的要求是一次获得一个文件的有效权限,我通过为三个子查询中的每一个分配优先级,按优先级顺序将它们与 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;
现在,这可能不是特别有效,但到目前为止它已经起作用了。
我现在的问题是扩展它以检索用户对多个文件的有效权限。由于优先级结构,现有查询无法做到这一点。
我应该能够在三个 table 中使用 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
来编写查询?
作为奖励,是否有更好的方法来达到相同的结果?
作为脚注:整个结构需要及时审查,但那个时间不是现在。这是我必须使用的,直到后来的一些开发提示我们实现更好的东西。
您可以通过将所有您感兴趣的文件合并在一起来创建一个内联视图,而不是使用 where in
。这将维护查询链的outer
结尾
例如:
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