2016-08-19 63 views
0

我學習的Oracle SQL用其原始HR模式工作,其中有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 = ),並將其與員工的(在這種情況下,)進行比較。另外,在上述採樣數據,輸出應該是:

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

在那裏我們有四(4)在部門,和$ 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 

不過,我覺得應該有獲得更好的方法相同的結果與更少的自我連接。有沒有辦法獲得更好的表現?

+0

你能告訴我們對經理來說是什麼樣的記錄? –

+0

請澄清......對於您給出的例子,您希望60部門的平均工資,但不是該部門的所有員工的平均工資,而僅僅是爲管理人員的員工? (當然包括原僱員的經理。) – mathguy

+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 
; 
+0

'我有興趣獲得部門60中所有經理的平均工資,並將其與員工(在本例中爲140)進行比較。' –

+0

@TimBiegeleisen部門60中所有**經理**的平均工資。我明白了。爲什麼**員工**工資的平均水平?另外,爲什麼這是在我的答案下,而不是在你的答案下? – mathguy

+0

@TimBiegeleisen - 我再次回顧OP的要求和他的樣本輸出(部分原樣)以及他試圖解決的問題,他們都同意。對於每個有經理的員工,他都希望顯示該員工,他或她的工資(單個!),經理ID,經理部門(有時與員工不同!)以及經理部門的平均工資。 (但是,我剛剛注意到他不想要該部門的所有員工......所以我的解決方案也不正確。) – mathguy

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 
+0

爲什麼員工的平均工資?我沒有看到這個要求。 – mathguy

+0

不等同:原始聲明將員工加入經理,而不是基於部門 - 再次檢查樣本數據。結果列和排序中的一些其他差異。 'IN'不需要'DISTINCT',並且有可能這兩種形式無論如何會減少到相同的計劃(如果輸出數據是相同的)。 –

+0

@ Clockwork-Muse鑑於OP中糟糕的解釋,這是我當時能做的最好的。如果它更新,我也會更新。 –