【问题标题】:SQL Query joins to seemingly loop non existent matches in second tableSQL Query 连接到第二个表中看似循环不存在的匹配项
【发布时间】:2020-01-19 20:52:42
【问题描述】:

我正在尝试编写一个查询,该查询将输出用户不属于角色的所有情况。

我试图将此查询限制为尽可能简单(没有循环,)。

我的例子中的表结构是这样的:

  • Team:

    ID | UserID | RoleID
    ---+--------+-------
    1  | 0      | 0
    2  | 0      | 1
    3  | 0      | 2
    4  | 1      | 0
    5  | 1      | 2
    
  • Roles:

    RoleID | Name
    -------+-----
    0      | AAA
    1      | BBB
    2      | CCC
    3      | DDD
    4      | EEE
    

期望的输出:

UserID | RoleID
-------+-------
0      | 3
0      | 4
1      | 1
1      | 3
1      | 4

我目前使用的代码是:

SELECT *
FROM Team t
RIGHT OUTER JOIN Roles r ON t.RoleID = r.RoleID
LEFT JOIN Roles r1 ON t.RoleID = r1.RoleID
WHERE r.RoleID IS NULL

【问题讨论】:

  • 右连接与左连接?!?没有人能理解...

标签: sql left-join outer-join


【解决方案1】:

您可以CROSS JOIN 团队和角色生成所有可能的组合,然后使用LEFT JOIN 反模式找出哪些组合不存在:

SELECT DISTINCT t.UserID, r.RoleID
FROM Team t
CROSS JOIN Roles r
LEFT JOIN Team t1 ON t1.RoleID = r.RoleID AND t1.userID = t.UserID
WHERE t1.UserID IS NULL
ORDER BY t.UserID, r.RoleID

Demo on DB Fiddle 与您的示例数据返回:

| UserID | RoleID |
| ------ | ------ |
| 0      | 3      |
| 0      | 4      |
| 1      | 1      |
| 1      | 3      |
| 1      | 4      |

【讨论】:

    【解决方案2】:

    我主张使用cross join 生成行,然后过滤掉已经存在的行(使用left joinnot in):

    select u.userid, r.roleid
    from (select distinct userid from team) u cross join
         roles r left join
         team t
         on t.userid = u.userid and t.role_id = r.roleid
    where t.userid is null;
    

    如果您有单独的用户表,则可以使用该表代替子查询。与在外部查询中使用 select distinct/group by 的方法相比,这应该有两个优点:

    • 索引可用于(select distinct) 子查询u
    • 无需对完整结果集进行处理即可删除重复项。

    【讨论】:

      猜你喜欢
      • 2013-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-05
      • 2020-08-31
      相关资源
      最近更新 更多