問題:查找某個列中值的模式(數學中的模式概念就是對于給定的數據集出現最頻繁的元素)。例如,查找DEPTNO 20中工資的模式。例如下列工資:
select sal
from emp
where deptno = 20
order by sal
SAL
----------
800
1100
2975
3000
3000
the mode is 3000.
解決方案
DB2和SQL Server
使用窗口函數DENSE_RANK,把工資重復出現次數分等級,以便提取模式:
1 select sal
2 from (
3 select sal,
4 dense_rank()over(order by cnt desc) as rnk
5 from (
6 select sal, count(*) as cnt
8 from emp
9 where deptno = 20
10 group by sal
11 ) x
12 ) y
13 where rnk = 1
Oracle
在Oracle8i Database中,可以使用DB2給出的解決方案。對于Oracle9i及更高版本,可以用聚集函數MAX的KEEP擴展,以得到SAL模式。特別要注意的是,如果存在綁帶,也即多個行都是模式,則采用KEEP方案僅能得到一個,即其中工資最高的那個。如果想要看所有模式(如果存在多個模式),則必須修改該方案,或者簡單地使用前面介紹的DB2解決方案。在這個例子中,由于3000是DEPTNO 20中SAL的模式,而且它也是最高的SAL,因此以下方案就可以了:
1 select max(sal)
2 keep(dense_rank first order by cnt desc) sal
3 from (
4 select sal, count(*) cnt
5 from emp
6 where deptno=20
7 group by sal
8 )
MySQL和PostgreSQL
使用子查詢查找模式:
1 select sal
2 from emp
3 where deptno = 20
4 group by sal
5 having count(*) >= all ( select count(*)
6 from emp
7 where deptno = 20
8 group by sal )
討論
DB2和SQL Server
內聯視圖X將返回每個SAL及它出現的次數。內聯視圖Y使用窗口函數DENSE_RANK(它允許綁帶)給結果排序。結果按每個SAL出現的次數分等級,如下所示:
1 select sal,
2 dense_rank()over(order by cnt desc) as rnk
3 from (
4 select sal,count(*) as cnt
5 from emp
6 where deptno = 20
7 group by sal
8 ) x
SAL RNK
----- ----------
3000 1
800 2
1100 2
2975 2
最外層的查詢只簡單地保留RNK為1的行。
Oracle
內聯視圖將返回所有SAL及其出現的次數,如下所示:
select sal, count(*) cnt
from emp
where deptno=20
group by sal
SAL CNT
----- ----------
800 1
1100 1
2975 1
3000 2
下一步,使用聚集函數MAX的KEEP擴展查找模式。如果仔細分析下面給出的KEEP子句,會發現它又有三個子句,即DENSE_RANK、FIRST和ORDER BY CNT DESC:
keep(dense_rank first order by cnt desc)
這種做法對求模式極其方便。KEEP子句根據內聯視圖返回的CNT值來確定MAX返回SAL的哪個值。按從右向左的方向將CNT遞減排序,然后保留下按DENSE_RANK次序返回的所有CNT值的第一個值。查看一下內聯視圖的結果集,就會看到3000具有最高的CNT值 —— 2。MAX(SAL) 返回的是擁有最高CNT值的最大SAL,在本例中是3000。
有關Oracle中集合函數的KEEP擴展的深入討論,請參閱第11章第11.11節。有關Oracle中集合函數的KEEP擴展的深入討論,請參閱第11章第11.11節。
MySQL和PostgreSQL
子查詢將返回每個SAL出現的次數。外層查詢將返回其的出現次數大于等于子查詢所返回所有計數值的SAL(換句話說,外層查詢會返回DEPTNO 20中出現最多的工資)。