SQL - выбор пар пользователей с разным идентификатором группы - PullRequest
3 голосов
/ 09 апреля 2020

Мне нужно написать запрос в SQL, который возвращает пары пользователей (имя и фамилия), которые никогда не ассоциируются вместе в одной группе.

GROUP

idGroup
idUser (Foreign key)

ПОЛЬЗОВАТЕЛЬ

idUser (Primary key)
Name 
Surname

Я пробовал это, но это не работает, почему?

SELECT u1.name, u1.surname, u2.name, u2.surname 
FROM group g1
JOIN group g2 ON g2.idgroup = g1.idgroup
JOIN user u1  ON u1.userid = g1.iduser
JOIN user u2  ON u2.userid = g2.iduser
WHERE g2.idgroup <> g1.idgroup

Ответы [ 3 ]

2 голосов
/ 09 апреля 2020

Я думаю not exists:

select u1.iduser, u2.iduser
from users u1 join
     users u2
     on u1.iduser < u2.iduser
where not exists (select 1
                  from usergroups ug1 join
                       usergroups ug2
                       on ug1.idgroup = ug2.idgroup
                  where ug1.iduser = u1.iduser and
                        ug2.iduser = u2.iduser
                 );
2 голосов
/ 09 апреля 2020

Ваша попытка не удалась, потому что она просто проверяет, есть ли у пары пользователей хотя бы одна общая группа, а вы хотите проверить, различны ли все группы.

Вы можете самостоятельно присоединиться к таблице users, чтобы сгенерировать все возможные пары пользователей, а затем использовать not exists с совокупным коррелированным подзапросом, чтобы убедиться, что не существует группы, в которой появляются оба пользователя:

select u1.name name1, u1.surname surname1, u2.name name2, u2.surname surname2
from users u1
inner join users u2 on u1.id_user < u2.id_user
where not exists (
    select 1
    from groups g
    group by g.id_group
    having 
            max(case when g.id_user = u1.id_user then 1 end) = 1 
        and max(case when g.id_user = u2.id_user then 1 end) = 1
)
1 голос
/ 09 апреля 2020

В конце концов, это всего лишь комбинации для двух пользователей, кроме найденных в группе. В основном у нас есть MINUS, NOT EXISTS и NOT IN.

МИНУС

select u1.iduser, u2.iduser from "USER" u1 join "USER" u2 on u1.iduser < u2.iduser
minus
select g1.iduser, g2.iduser from "GROUP" g1 join "GROUP" g2 on g1.idgroup = g2.idgroup 
                                                           and g1.iduser < g2.iduser

НЕ В

select u1.iduser, u2.iduser from "USER" u1 join "USER" u2 on u1.iduser < u2.iduser
where (u1.iduser, u2.iduser) not in
(
  select g1.iduser, g2.iduser from "GROUP" g1 join "GROUP" g2 on g1.idgroup = g2.idgroup 
                                                             and g1.iduser < g2.iduser
)

НЕ СУЩЕСТВУЕТ

select u1.iduser, u2.iduser from "USER" u1 join "USER" u2 on u1.iduser < u2.iduser
where not exists
(
  select null from "GROUP" g1 join "GROUP" g2 on g1.idgroup = g2.idgroup 
  where g1.iduser = u1.iduser
    and g2.iduser = u2.iduser
)

Как видите, три запроса мало чем отличаются. Хотя запрос MINUS выглядит наиболее простым, он имеет тот недостаток, что вы не можете напрямую отображать имена пользователей, если хотите. EXISTS подзапросы выглядят немного сложнее, чем IN подзапросы. (NOT IN содержит ловушку, хотя значения могут быть нулевыми, что здесь не так.) Мой выбор будет NOT IN здесь, но просто выберите то, что вам больше нравится.

(На примечание: USER и GROUP являются ключевыми словами SQL и, по моему мнению, не являются хорошим выбором для имен таблиц.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...