使用单个mysql查询为用户获取组(仅允许)

时间:2014-07-18 10:40:43

标签: mysql sql join

最近我遇到了一个有趣的问题。让我们添加一些表,即User,Group及其Join表User_Group。以下是表格的虚拟表示

用户

user_id | user_name 
  1     |  a
  2     |  b
  3     |  c

group_id | group_code
  1      |  G1
  2      |  G2
  3      |  G3

USER_GROUP

userid  | groupid | exclusion
  1     |   1     |  0
  1     |   2     |  0
  2     |   1     |  1 

问题是获取他有权访问的用户的组列表。 组中用户访问的一般假设是:

  • 如果用户在User_group连接表中没有条目,则用户可以访问 所有组(即G1,G2和G3)
  • 如果用户在User_Group中有条目 排除0然后该用户只能访问该组(用户1具有 访问G1和g2)
  • 如果用户在User_Group中输入了排除项 1然后该用户在该组中没有访问权限但他有权访问 其他所有其他组(用户2仅在g1上被拒绝,应该有 访问G2和G3)

这是查询案例1& 3但案例2失败。

SELECT g.id, g.code, ug.user_groups_id, ug.exclusion FROM group g
LEFT JOIN user_group ug ON ug.group_id = g.id 
     AND ug.user_id = 1 -- works for user 2 and 3 but fails for user 1         
WHERE (ug.exclusion = 0 OR ug.exclusion IS NULL) 

请建议我们是否只使用单一查询获取群组列表

1 个答案:

答案 0 :(得分:2)

有趣的问题。

您可以通过生成所有用户和所有组的列表来解决此问题(使用cross join)。然后使用left join匹配回已知的组列表。那么逻辑就是:

  1. 案例1是在没有匹配时使用所有组。
  2. 案例2仅使用匹配的组。
  3. 案例3仅使用不匹配的组。
  4. 以下是查询:

    select u.userid,
           (case when max(ug.exclusion) is null  -- all groups
                 then group_concat(g.groupcode)
                 when max(ug.exclusion) = 0   -- only those included
                 then group_concat(case when ug.groupid is not null then g.groupcode end)
                 when max(ug.exclusion) = 1   -- exclude these
                 then group_concat(case when ug.groupid is null then g.groupcode end)
            end)
    from users u cross join
         groups g left join
         user_groups ug
         on u.userid = ug.userid and g.groupid = ug.groupid 
    group by u.userid;
    

    请注意,这只会在聚合中使用排除标志 - 基本上假设它在user_groups中的所有行上都相同。实际上,此标记可能位于user级别,而不是user_groups级别。这个假设与样本数据和问题的解释一致。