2015-12-21 61 views
0

我讀了一些甲骨文的SQL資源,我發現這個SQL代碼:聚合函數的分組列作爲連接條件?

SELECT e.ename AS "NAME", 
     e.sal AS "Salary", 
     e.deptno, 
     AVG(a.sal) dept_avg 
FROM emp e, emp a 
WHERE e.deptno = a.deptno 
AND e.sal > (SELECT AVG(sal) 
       FROM emp 
       WHERE deptno = e.deptno) 
GROUP BY e.ename, e.sal, e.deptno; 

這SQL代碼應該回報每一位員工即獲得比他的部門的平均工資越來越顯示他的名字,他的工資他部門ID和他部門的平均工資。

爲了返回dept_avg,我們必須group bydeptno,但分組列很奇怪。我猜想,分組列是用作連接條件的列,即a.deptno。真的嗎 ?如果沒有人可以澄清它嗎?

+1

這就是爲什麼使用舊式連接是愚蠢的。 – Hogan

+0

我不認爲用'INNER JOIN'重寫這個查詢會讓它更好。 – Timekiller

+0

@Timekiller爲什麼不呢? – Hogan

回答

1

如果您刪除GROUP BY並使用SELECT *,您會看到發生了什麼。

emp被加入自己,每個員工的薪水高於平均水平,他的部門中的每一個員工都會加入,造成很多行。然後,從這些數據中,使用GROUP BY再次計算平均工資(來自部門中其他每個工人)的平均工資。它效率非常低,看看其他答案,看看它應該如何完成。

+1

我喜歡那個......「imprssively效率低」大聲笑 – Hogan

+0

如果聽起來很奇怪,請減少我一些鬆懈 - 我不是母語:3 – Timekiller

+0

不,這不奇怪,這很有趣,很重要。 – Hogan

2

也許用更現代的約定重寫會使它更清晰?

WITH avgbydept as 
(
    SELECT deptno, avg(sal) as avgsal 
    FROM emp 
    GROUP BY deptno 
) 
SELECT e.ename AS "NAME", 
     e.sal AS "Salary", 
     e.deptno, 
     AVG(a.sal) dept_avg 
FROM emp e 
JOIN emp a ON e.deptno = a.deptno 
JOIN avgbydept abd ON e.deptno = abd.deptno 
WHERE e.sal > abd.avgsal 
GROUP BY e.ename, e.sal, e.deptno; 

一兩件事,這使得清楚的是,它有一個額外的「錯誤」加入和group by - 要照你說:

這個SQL代碼應該返回每一位員工即獲得超過其部門平均工資的 ,並顯示他的姓名,他的工資 他的部門ID以及他所在部門的平均工資。

我相信你想這個

WITH avgbydept as 
(
    SELECT deptno, avg(sal) as avgsal 
    FROM emp 
    GROUP BY deptno 
) 
SELECT e.ename AS "NAME", 
     e.sal AS "Salary", 
     e.deptno, 
     abd.avgsal as dept_avg 
FROM emp e 
JOIN avgbydept abd ON e.deptno = abd.deptno 
WHERE e.sal > abd.avgsal 
1

GROUP BY可以把我們的循環。這裏有一個簡單的方法來思考分組:

select field1, field1, sum(field3) 
from .. 
group by <all fields that do not participate in aggregate> 

你注意到可能會略有重新編寫這樣的查詢:

select e.*, t.avgsal 
from emp e 
inner join (select deptno, avg(sal) avgsal from emp group by deptno) t 
    on e.deptno = t.deptno 
where e.sal > t.avgsal 

現在你可以看到,t別名的子查詢會得到平均工資由部門。然後,我們使用部門加入員工,並按部門加入我們的平均工資,並且不需要進行分組。