MySQL где в списке, но не во временной таблице - PullRequest
0 голосов
/ 19 июня 2020

Я рассматриваю следующие 2 таблицы

|------------|  |-----------|
| user_roles |  |   roles   | 
|============|  |===========|
| user_id    |  | role_id   |
| role_id    |  | code_name |
|------------|  |-----------|

Я хочу получить все user_roles, где user_id в данном списке user_ids. Но я хочу исключить всех пользователей, у которых есть роль с code_name = 'special_role'.

Как лучше всего это сделать?

В качестве примера предположим, что у меня есть следующее:

user_roles:             roles:

| user_id | role_id |   | role_id |  code_name   |
|=========|=========|   |=========|==============|
|    1    |    1    |   |    1    | special_role |
|    1    |    2    |   |    2    | another_role |
|    2    |    2    |   |---------|--------------|
|    3    |    2    |
|---------|---------|

Я думал использовать временные таблицы, например:

create temporary table if not exists all_user_ids as (
  select ur.user_id as user_id, ur.role_id as role_id
  from user_roles ur
  where ur.user_id in (1,2,3)
);

create temporary table if not exists special_user_ids as (
  select aui.user_id as user_id
  from all_user_ids aui
  join roles r on r.role_id = aui.role_id
  where r.code_name = 'special_role'
);

create temporary table if not exists non_special_user_ids as (
  select aui.user_id as user_id
  from all_user_ids aui
  where aui.user_id not in (special_user_ids.user_id)
);

Тогда для моего окончательного результата я мог бы сделать:

select ur.user_id, ur.role_id
from user_roles ur
where ur.user_id in (non_special_user_ids.user_id)

Но должен быть способ получше ?!

Ответы [ 3 ]

1 голос
/ 19 июня 2020

Вы можете использовать оконные функции - если вы используете MySQL 8.0:

select *
from (
    select ur.*, r.code_name, max(r.code_name = 'special_role') over(partition by user_id) has_special_role
    from user_roles ur
    inner join roles r on r.role_id = ur.role_id
) t
where has_special_role = 0

В более ранних версиях одним из методов является not exists:

select ur.*
from user_roles ur
where not exists (
    select 1 
    from user_roles ur1
    inner join roles r1 on r1.role_id = ur1.role_id
    where ur1.user_id = ur.user_id and r1.code_name = 'special_role'
)
0 голосов
/ 19 июня 2020

Используйте IN и NOT IN для 2 условий:

select *
from user_roles
where user_id in (<list of usr_ids>)
and user_id not in (
  select user_id from user_roles 
  where role_id = (select role_id from roles where code_name = 'special_role')
)

См. demo .

0 голосов
/ 19 июня 2020

Просто присоединяйтесь. Это должно быть довольно быстро, если у вас настроены ключи.

SELECT * FROM user_roles JOIN role ON user_roles.role_id = role.role_id 
    WHERE user_roles.user_id IN(1,2,3 ...) AND role.code_name != "special_role"

Неправильно понял вопрос. Если вы не хотите, чтобы пользователи вообще имели особую роль:

SELECT * FROM user_roles WHERE user_id NOT IN(
    SELECT user_id FROM user_roles JOIN role ON user_role.role_id = role.role_id
        WHERE role.role_code = 'special_role')
    AND user_id IN (1, 2, 3 ...)
...