左外连接、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

quick demo here