問題:計算平均數,但希望排除最大和最小值,以(希望能)減少數據畸偏造成的影響。例如,計算除最高和最低工資外的所有職員的平均工資。
解決方案
MySQL和PostgreSQL
使用子查詢排除最高和最低值:
1 select avg(sal)
2 from emp
3 where sal not in (
4 (select min(sal) from emp),
5 (select max(sal) from emp)
6 )
DB2、Oracle和SQL Server
使用內聯視圖及窗口函數MAX OVER和MIN OVER,生成一個結果集,可以很容易地從中剔除最大和最小值:
1 select avg(sal)
2 from (
3 select sal, min(sal)over() min_sal, max(sal)over() max_sal
4 from emp
5 ) x
6 where sal not in (min_sal,max_sal)
討論
MySQL和PostgreSQL
子查詢返回表中的最高工資和最低工資。針對返回的值使用NOT IN,就可以從平均值中排除最高工資和最低工資。記住,如果存在重復(多個職員都是最高或最低工資),那么他們都會被排除在平均值之外。如果只想排除一個最高和最低值,只需從SUM中減去它們,再做除法:
select (sum(sal)-min(sal)-max(sal))/(count(*)-2)
from emp
DB2、Oracle和SQL Server
內聯視圖X將返回所有工資,其中包括最高工資和最低工資:
select sal, min(sal)over() min_sal, max(sal)over() max_sal
from emp
SAL MIN_SAL MAX_SAL
--------- --------- ---------
800 800 5000
1600 800 5000
1250 800 5000
2975 800 5000
1250 800 5000
2850 800 5000
2450 800 5000
3000 800 5000
5000 800 5000
1500 800 5000
1100 800 5000
950 800 5000
3000 800 5000
1300 800 5000
從每一行都可以訪問最高工資和最低工資,因此,要找出哪些工資是最高工資的和/或最低工資的非常簡單。外層查詢會對內聯視圖X返回的行作篩選,這樣,所有與MIN_SAL和MAX_SALAN相匹配的行都會從平均值中排除掉。