【问题标题】:SQL question - How to get employees with the same skills as a specific employeeSQL 问题 - 如何让员工拥有与特定员工相同的技能
【发布时间】:2020-10-01 20:37:44
【问题描述】:

我有一个名为 Employee 的表,其中包含列:

  • EMPID INT(主键)
  • EMPNAME VARCHAR2(100)

样本数据如下:

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

我有另一个表Employee_Skills 有列:

  • EMPID INT
  • 技能 VARCHAR2(100)

其中的一个样本可以表示如下:

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

在第二张表中,两列共同构成主键。而EMPID 有一个引用约束指向Employee(EMPID)

我希望所有员工都具备 Mary 所拥有的所有技能。

例如,

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

此查询返回以下行:

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

现在我想选择所有具备上述技能的员工(可以拥有更多技能,但至少应该具备 Mary 拥有的技能)。

我做了一些尝试,但没有什么能完全满足我的需要。

这是一次失败的尝试:

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');

【问题讨论】:

  • 请提供代表性数据并标记您正在使用的特定 DBMS(Oracle、Postgres、DB2、Microsoft SQL Server)

标签: sql oracle count relational-division


【解决方案1】:

您可以通过连接和聚合来解决这种关系划分问题:

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】:

    有很多方法可以解决这个问题,其中最直观的一种可能是:

    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:我从返回的列表中排除了 Mary。

    我按如下方式重新创建了您的数据:

    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');          
                    
    

    【讨论】:

    • 谢谢,拉斯。在您给出的示例中,玛丽有 5 个技能。 Bob 只有 2 个。所以 Bob 不应该出现在最终结果中。
    • 我明白了。我错过了那部分要求。我已经相应地更新了我的答案。
    【解决方案3】:

    这已经奏效了。分享给大家。基本上,你掌握了玛丽的技能。减去当前员工的技能。如果你得到一个空白,你会在结果中显示这个员工。

    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';
    
    

    【讨论】:

    • 这是特定于 Oracle 的。我用 Oracle 标记了你的问题(因为 Varchar2 类型)和minus 你在这里演示的方式是另一个 Oracle 特性。
    猜你喜欢
    • 1970-01-01
    • 2022-07-21
    • 2022-10-08
    • 2022-01-14
    • 1970-01-01
    • 1970-01-01
    • 2021-04-14
    • 1970-01-01
    • 2011-01-13
    相关资源
    最近更新 更多