如何改善这种自我联系

时间:2016-08-19 01:39:05

标签: sql oracle self-join

我正在通过使用其原始HR模式学习Oracle SQL,其中有EMPLOYEES表,其中有三列我主要感兴趣的是:MANAGER_ID,这基本上是一个自引用EMPLOYEES.EMPLOYEE_IDDEPARTMENT_IDSALARY。 (您可以在此处找到schema diagramschema objects

我希望每位员工能够检索他/她SALARY,以及员工经理的部门平均工资。例如,如果我们有以下内容(EMPLOYEE_ID = 140是此处感兴趣的一方):

+-------------+--------+---------------+------------+
| EMPLOYEE_ID | SALARY | DEPARTMENT_ID | MANAGER_ID |
+-------------+--------+---------------+------------+
| 140         | 12000  | 50            | 110        |
| 110         | 20000  | 60            | 101        |
| 156         | 18000  | 60            | 101        |
| 175         | 15000  | 60            | 105        |
| 320         | 24000  | 60            | 105        |
+-------------+--------+---------------+------------+

我有兴趣获得部门中所有管理人员(并非所有其他非管理人员)的平均工资,其中员工的经理工作(在这种情况下, DEPARTMENT_ID = 60 ),并将其与员工进行比较(在这种情况下, 140 )。在上面的示例数据中,输出应为:

+-------------+--------+-------------+-------------+------------+
| EMPLOYEE_ID | SALARY | AVG_MGR_SAL | MGR_DEPT_ID | MANAGER_ID |
+-------------+--------+-------------+-------------+------------+
| 140         | 12000  | 19250       | 60          | 110        |
+-------------+--------+-------------+-------------+------------+

我们有四(4)名经理在部门 60 工作, $ 19250 计算为(20000 + 18000 + 15000 + 24000)/ 4.我来了使用以下似乎有效的查询(并排除那些没有经理的员工):

select
    employee_id
    , salary employee_salary
    , trunc(mgr_info.avg_manager_salary_per_dept, 0) emp_manager_avg_sal_dept
    , mgr_info.manager_dept_id
    , mgr_info.manager_id
from employees
join (
      select
          e1.employee_id manager_id
          , e1.department_id manager_dept_id
          , e1.salary manager_salary
          , avg(e1.salary) over (partition by e1.department_id) avg_manager_salary_per_dept
      from employees e1
      join (
            select distinct manager_id 
            from employees 
            where manager_id is not null
           ) mgr_ids
          on e1.employee_id = mgr_ids.manager_id
      ) mgr_info
    on employees.manager_id = mgr_info.manager_id
order by employee_id

但是,我觉得应该有更好的方法来获得相同的结果,减少自连接。有没有办法获得更好的表现?

2 个答案:

答案 0 :(得分:0)

这样的事情......你只需要一次加入,你就可以计算经理人的经理部门的平均工资"表的副本。我只包括几个列,您可能需要更多或更少,但我相信您想要的核心内容。

(注:编辑,因为我意识到我错过了要求中的一个细节)

select e.employee_id   as employee_id,
       e.salary        as employee_salary,
       m.employee_id   as manager_id,
       m.department_id as manager_dept_id,
       m.avg_salary    as avg_sal_of_mgr_dept
from hr.employees e inner join
       ( select employee_id, department_id, 
                avg(salary) over (partition by department_id) as avg_salary
         from   hr.employees
         where  employee_id in (select manager_id from hr.employees)
       ) m
on e.manager_id = m.employee_id
;

答案 1 :(得分:0)

这是一个使用一系列连接来获得结果的选项:

SELECT DISTINCT t1.EMPLOYEE_ID,
                t1.SALARY,
                t1.DEPARTMENT_ID,
                COALESCE(t2.SALARY, 0.0) AS ManagerAvgSal
FROM employees t1
LEFT JOIN
(
    SELECT e1.DEPARTMENT_ID, AVG(e1.SALARY) AS SALARY
    FROM employees e1
    WHERE e1.EMPLOYEE_ID IN (SELECT DISTINCT MANAGER_ID FROM employees)
    GROUP BY e1.DEPARTMENT_ID
) t2
    ON t1.DEPARTMENT_ID = t2.DEPARTMENT_ID