SQL question - How to get employees with the same skills as a specific employee

1.2k Views Asked by At

I have a table called Employee with columns:

  • EMPID INT (primary key)
  • EMPNAME VARCHAR2(100)

With sample data as follows:

empid|empname|
-----|-------|
    1|Mary   |
    2|Bob    |

I have another table Employee_Skills with columns:

  • EMPID INT
  • SKILL VARCHAR2(100)

A sample of which can be represented as follows:

empid|skill |
-----|------|
    1|SKILL |
    1|Java  |
    1|C++   |
    1|Python|
    2|C++   |
    2|Python|

In the 2nd table, both the columns together form the primary key. And EMPID has a referential constraint pointing to Employee(EMPID).

I want to get all the employees who have all the skills that Mary has.

For example,

select t2.skill 
from Employee t1 
join Employee_Skills t2 on (t1.EMPID = t2.EMPID) 
where t1.EMPNAME = 'Mary'

This query returned these rows:

SKILL
------------
Java
C++
Python
... (a few more)

Now I want to select all employees that have the above skills (can have more skills, but should have at least the ones that Mary has).

I have made a few attempts but nothing gives me exactly what I need.

Here's one attempt that didn't work:

select t1.EMPID, t1.EMPNAME
from Employees t1 
join Employee_Skills t2 on (t1.EMPID = t2.EMPID)
where t2.SKILL = ALL (select t4.skill 
                      from Employee t3  
                      join Employee_Skills t4 on (t3.EMPID = t4.EMPID) 
                      where t3.EMPNAME = 'Mary');
3

There are 3 best solutions below

1
On BEST ANSWER

This has worked. Sharing it for everyone. Basically, you take Mary's skills. Do a MINUS of the current employee's skills. If you get a blank, you show this employee in the result.

Select t4.empid, t4.empname from employee t4
Where not exists 
(Select t1.skill from employee_skills t1 join employee t2 on (t1.empid = t2.empid) where t2.empname = 'Mary'
Minus
Select t3.skill from employee_skills t3 where t3.empid = t4.empid)
and t4.empname <> 'Mary';

0
On

You can solve this relational division problem with joins and aggregation:

select e2.empid
from employee e1
inner join employee_skills es1 on es1.empid = e1.empid
inner join employee_skills es2 on es2.skill = es1.skill and es2.empid <> es1.empid 
inner join employee e2 on e2.empid = es2.empid
where e1.empname = 'Mary'
group by e2.empid
having count(*) = (
    select count(*)
    from employee e3
    inner join employee_skills es3 on es3.empid = e3.empid
    where e3.empname = 'Mary'
)
2
On

There are many ways to solve this, one of the most intuitive of which is probably the following:

select emp.empid, emp.empname
from Employee_Skills esk
inner join employee emp
 on emp.empid = esk.empid
where emp.empname <> 'Mary' 
 and exists (select null   
                from employee_skills esk_
                 inner join employee emp_
                  on emp_.empid = esk_.empid
                where emp_.empname = 'Mary'
                 and esk_.skill = esk.skill);

PS: I excluded Mary from the list returned.

I recreated your data as follows:

create table employee(EMPID INT , EMPNAME VARCHAR(100));
                                                   
create table Employee_Skills(EMPID INT, SKILL VARCHAR(100));
                                                       
insert into employee values (1, 'Mary');
insert into employee values (2, 'Bob');
                                                       
insert into employee_skills values (2, 'SKILL');
insert into employee_skills values (2, 'Java');
insert into employee_skills values (1, 'C++');
insert into employee_skills values (1, 'Python');                                 
insert into employee_skills values (2, 'C++');
insert into employee_skills values (2, 'Python');