SQL-запрос объединяет, казалось бы, цикл несуществующих совпадений во второй таблице - PullRequest
1 голос
/ 18 сентября 2019

Я пытаюсь выписать запрос, который будет выводить все случаи, когда пользователь не является частью роли.

Я пытаюсь ограничить этот запрос как можно более простым (без циклов, и т.д. ).

Структура таблицы в моем примере выглядит следующим образом:

  • Таблица 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

Ответы [ 2 ]

0 голосов
/ 19 сентября 2019

Я рекомендую генерировать строки, используя cross join, а затем отфильтровывать уже существующие строки (используя left join или not 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.
  • Для полного удаления дубликатов обработка полного набора результатов не требуется.
0 голосов
/ 18 сентября 2019

Вы можете 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

Это Демонстрация на DB Fiddle с вашими примерами возвращаемых данных:

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