(1)oracle使用keep分析函數取最值記錄
-- 取工資sal最大的雇員姓名及其工資,以及工資sal最少的雇員姓名及其工資 select deptno, empno, ename, sal, max(ename) keep(dense_rank FIRST order by sal) over (partition by deptno) as min_sal_man, max(sal) keep(dense_rank FIRST order by sal) over (partition by deptno) as min_sal, max(ename) keep(dense_rank LAST order by sal) over (partition by deptno) as max_sal_man, max(sal) keep(dense_rank LAST order by sal) over (partition by deptno) as max_sal from emp where deptno=10
結果如下:
從語句中可以看到,ename和sal都是用的max(),這樣做的目的是為了去除由於keep()函數得到的有重復值的數據結果集。這樣用有一個弊端,加入部門20有兩個相同的最大SAL的人,部門30有兩個相同的最小SAL的人,如果按照這種方法取出來的數據,就不一定准確了,重復的人會被去除掉。
我們用下面的語句來修改一下:
select deptno, empno, ename, sal, max(ename) keep(dense_rank FIRST order by sal) over (partition by deptno) as min_sal_man, max(sal) keep(dense_rank FIRST order by sal) over (partition by deptno) as min_sal, max(ename) keep(dense_rank LAST order by sal) over (partition by deptno) as max_sal_man, max(sal) keep(dense_rank LAST order by sal) over (partition by deptno) as max_sal, wmsys.wm_concat(ename) keep(dense_rank LAST order by sal) over (partition by deptno) as 工資最高的人, wmsys.wm_concat(ename) keep(dense_rank FIRST order by sal) over (partition by deptno) as 工資最低的人 from emp where deptno=20 order by 1, 2 ;
我們新增了兩個列:工資最高的人,工資最低的人。執行看一下結果:
可以看到,deptno=20時,SCOTT和FORD兩個人的工資SAL都是3000,如果用MAX()就只能取出其中一個人的姓名,顯然是不對的。
然后,我們再來看一下deptno=30時的情況:
select deptno, empno, ename, sal, max(ename) keep(dense_rank FIRST order by sal) over (partition by deptno) as min_sal_man, max(sal) keep(dense_rank FIRST order by sal) over (partition by deptno) as min_sal, max(ename) keep(dense_rank LAST order by sal) over (partition by deptno) as max_sal_man, max(sal) keep(dense_rank LAST order by sal) over (partition by deptno) as max_sal, wmsys.wm_concat(ename) keep(dense_rank LAST order by sal) over (partition by deptno) as 工資最高的人, wmsys.wm_concat(ename) keep(dense_rank FIRST order by sal) over (partition by deptno) as 工資最低的人 from emp where deptno=30 order by 1, 2 ;
deptno=30時的結果如下:
可以看到,deptno=30時,WARD和MARTIN兩人的工資最小且均為1250,如果用MAX()的方式,就只能取出其中一個人的名稱。
這就是因為keep()取出來的數據集是包含多個數據結果的,所以,在語句中使用了wmsys.wm_concat()函數,該函數的作用是以逗號分隔連接列的值。
注:wm_concat()的功能有點兒類似分析函數listagg() within group() 。
(2)使用SQL子查詢和聚合函數,查詢出最大值和最小值
-- 使用子查詢查詢出最大值和最小值 select * from ( select deptno, listagg(ename,',') within group (order by deptno) as dept_max_ename, max(sal) as dept_max_sal from emp where (deptno,sal) in (select deptno, max(sal) as max_sal from emp group by deptno) group by deptno ) A inner join ( select deptno, listagg(ename,',') within group (order by deptno) as dept_min_ename, min(sal) as dept_min_sal from emp where (deptno,sal) in (select deptno, min(sal) as min_sal from emp group by deptno) group by deptno ) B on A.deptno = B.deptno
結果如下:
在這個方案里面,還使用了listagg()分析函數將最值有重復姓名的人合並在一起,用wm_concat()函數替代listagg()也可以
wm_concat(ename) as dept_max_ename, wm_concat(ename) as dept_min_ename,
------------------------------------------------------------------------