Давайте начнем с этого.
create table works ( eid int not null, did int not null );
insert into works values (1,1), (1,1), (1,2), (1,3), (2,1), (2,2), (3,1), (4,4);
select * from works order by eid;
eid did
---------- ----------
1 1
1 1
1 2
1 3
2 1
2 2
3 1
4 4
Обратите внимание, что сотрудник 1 имеет несколько записей в отделе 1, криволинейный шар.
Чтобы выяснить, какие сотрудники находятся в более чем одном отделе, нам нужно объединить works
с самим собой, самостоятельное объединение . Это как любое другое объединение, но псевдонимы таблиц являются обязательными.
select wa.eid, wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did != wb.did;
Это объединяется с любой строкой, имеющей одинаковый идентификатор сотрудника, но другой идентификатор отдела, потому что мы не хотим видеть сотрудников в наших собственных отделах.
eid did did
---------- ---------- ----------
1 1 2
1 1 3
1 1 2
1 1 3
1 2 1
1 2 1
1 2 3
1 3 1
1 3 1
1 3 2
2 1 2
2 2 1
Сотрудник 1 отображается несколько раз, потому что он имеет несколько записей в works
, помните кривая мяч? Мы можем удалить эти дубликаты, выбрав только отдельные строки .
select distinct wa.eid, wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did != wb.did;
eid did did
---------- ---------- ----------
1 1 2
1 1 3
1 2 1
1 2 3
1 3 1
1 3 2
2 1 2
2 2 1
Мы также можем избежать подсчета каждой пары отделов дважды, присоединившись к wa.did < wb.did
вместо wa.did != wb.did
.
select distinct wa.eid, wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did < wb.did;
eid did did
---------- ---------- ----------
1 1 2
1 1 3
1 2 3
2 1 2
Теперь у нас есть список всех сотрудников, которые работают более чем в одном отделе, и их отделов.
Мы получаем общее количество сотрудников по , сгруппировав по оба идентификатора отдела и подсчитав сотрудников.
select count(distinct wa.eid) as num_eids_in_common,
wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did < wb.did
group by wa.did, wb.did;
num_eids_in_common did did
------------------ ---------- ----------
1 1 3
1 2 3
2 1 2
Наконец, мы получаем тот, который наиболее распространен, сортируя num_eids_in_common в порядке убывания и ограничивая его 1 строкой.
select count(distinct wa.eid) as num_eids_in_common,
wa.did, wb.did
from works wa
join works wb on wa.eid = wb.eid
and wa.did < wb.did
group by wa.did, wb.did
order by num_eids_in_common desc
limit 1;
num_eids_in_common did did
------------------ ---------- ----------
2 1 2