左外连接,WHERE子句和COALESCE

时间:2015-05-28 03:44:43

标签: mysql left-join outer-join

我有三张桌子:

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编写查询?

作为奖励,是否有更好的方法来实现相同的结果?

作为一个脚注:整个结构需要及时审查,但现在不是时候了。这是我必须要处理的,直到后来的一些开发提示我们更好地实现更好的东西。

1 个答案:

答案 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

quick demo here