兩道SQL面試題引出listagg函數:
1. 用一條sql求出每個部門(emp表)的最大工資和最小工資,以及最大工資和最小工資的員工姓名。
(注:一次表掃描。同一個部門最大工資或最小工資的人可能不止一個)。
2. 需求:有時為了方便打印,會要求多行多列打印,如打印emp.ename列,類似下面這樣顯示:
ALLEN JONES MARTIN SMITH WARD
BLAKE CLARK KING SCOTT TURNER
ADAMS FORD JAMES MILLER
listagg函數是oracle11.2以后推出的一個新函數,使用該函數實現了行轉列的功能,該數據與wmsys.wm_concat函數功能類似。
簡單的說就是在分組合並后,把某列數據逐個枚舉出來,其實也是一個行轉列的效果。
如下,原始數據:
實現效果:
sql語句舉例說明:
select nation, listagg(city,',') within group (order by city) as city
from test
group by nation
1:使用該函數必須的進行分組(group by 或使用分析函數進行分組)
2:listagg函數第一個參數表示需要進行枚舉的字段,第二個參數表示枚舉數據的分隔符
3:對於枚舉的字段同時還需要排序和分組within group(order by xx)
利用網絡上的例子:
with temp as( select 'China' nation ,'Guangzhou' city from dual union all select 'China' nation ,'Shanghai' city from dual union all select 'China' nation ,'Beijing' city from dual union all select 'USA' nation ,'New York' city from dual union all select 'USA' nation ,'Bostom' city from dual union all select 'Japan' nation ,'Tokyo' city from dual ) select nation,listagg(city,',') within GROUP (order by city) city from temp group by nation;
--利用wmsys.wm_concat實現相似的效果
with temp as( select 'China' nation ,'Guangzhou' city from dual union all select 'China' nation ,'Shanghai' city from dual union all select 'China' nation ,'Beijing' city from dual union all select 'USA' nation ,'New York' city from dual union all select 'USA' nation ,'Bostom' city from dual union all select 'Japan' nation ,'Tokyo' city from dual ) select nation,wmsys.wm_concat(city) from temp group by nation;
wmsys.wm_concat函數默認枚舉的數據是','分隔開的,而listagg可以自定義分隔符
--利用over(partition by XXX) 分析函數實現分組產生以上效果
with temp as( select 'China' nation ,'Guangzhou' city from dual union all select 'China' nation ,'Shanghai' city from dual union all select 'China' nation ,'Beijing' city from dual union all select 'USA' nation ,'New York' city from dual union all select 'USA' nation ,'Bostom' city from dual union all select 'Japan' nation ,'Tokyo' city from dual ) select nation, listagg(city,',') within GROUP (order by city) over (partition by nation) city from temp;
listagg函數作為分析函數的一部分存在。
理解完listagg函數上面的面試題也就容易多了,如下:
1. 用一條sql求出每個部門(emp表)的最大工資和最小工資,以及最大工資和最小工資的員工姓名。
(注:一次表掃描。同一個部門最大工資或最小工資的人可能不止一個)。
select deptno, max(sal) max_sal, listagg(decode(rn1, 1, ename, null), ',') within group(order by ename) max_sal_ename, min(sal) min_sal, listagg(decode(rn2, 1, ename, null), ',') within group(order by ename) min_sal_ename from (select deptno, ename, sal, dense_rank() over(partition by deptno order by sal desc) rn1, dense_rank() over(partition by deptno order by sal) rn2 from emp) where rn1 = 1 or rn2 = 1 group by deptno;
2. 需求:有時為了方便打印,會要求多行多列打印,如打印emp.ename列,類似下面這樣顯示:
ALLEN JONES MARTIN SMITH WARD
BLAKE CLARK KING SCOTT TURNER
ADAMS FORD JAMES MILLER
select deptno,listagg(ename,',') within group(order by ename) from emp t group by t.deptno; select wmsys.wm_concat(listagg(ename,',') within group(order by ename)) from emp t group by t.deptno;
參考:
http://www.2cto.com/database/201304/204096.html
http://www.2cto.com/database/201210/161494.html
http://dacoolbaby.iteye.com/blog/1698957
http://www.itpub.net/thread-1912275-1-1.html