Oracle高级分析函数与统计函数结合使用

这个blog我们来聊聊Oracle高级分析函数与统计统计函数结合使用

测试数据:

DROP TABLE testa;

CREATE TABLE testa (area VARCHAR2 (20), month VARCHAR2 (20),

amount NUMBER);

insert into testa values ('上海', '1', 199); 

insert into testa values ('上海', '2', 199); 

insert into testa values ('上海', '3', 155); 

insert into testa values ('上海', '3', 155); 

insert into testa values ('上海', '4', 125); 

insert into testa values ('广州', '1', 75); 

insert into testa values ('广州', '2', 67); 

insert into testa values ('北京', '1', 235);

insert into testa values ('北京', '2', 330); 

Commit;

一.keep函数

keep是Oracle下的另一个分析函数,他的用法不同于通过over关键字指定的分析函数,可以用于这样一种场合下:取同一个分组下以某个字段排序后,对指定字段取最小或最大的那个值。

keep语法:

min | max(col1) keep (dense_rank first | lastorder by col2) over (partion by col3); 

最前是聚合函数,可以是min、max、avg、sum...

col1为要计算的列;

dense_rank first,dense_rank last为keep 函数的保留属性,表示分组、排序结果集中第一个、最后一个;

解释:返回按照col3分组后,按照col2排序的结果集中第一个或最后一个最小值或最大值col1。

col1和col2列可重复

需求:求员工表每个员工信息及部门最高薪资、最低薪资

--传统sql写法,需要嵌套一层临时表

with tmp1 as

(

select e.deptno,max(e.sal) max_sal,min(e.sal) min_sal

from emp e

group by e.deptno

)

select e2.deptno,

e2.ename,

e2.sal,

max_sal,

min_sal

from emp e2

left join tmp1 

on e2.deptno = tmp1.deptno

ORDER BY e2.deptno, e2.sal, e2.ename;

--排名函数只能进行排名,通过排名可以看出最大和最小薪资,同样需要嵌套临时表来完成此类需求

--通过keep函数,无需嵌套子查询,代码逻辑更为简单 

SELECT Deptno,

Ename,

Sal,

MIN(Sal) KEEP(DENSE_RANK FIRST ORDER BY sal) OVER(PARTITION BY deptno) max_sal,

MAX(sal) KEEP(DENSE_RANK LAST ORDER BY sal) OVER(PARTITION BY deptno) min_sal

FROM Emp

ORDER BY deptno, sal, ename;

SQL> --传统sql写法,需要嵌套一层临时表

SQL> with tmp1 as

2 (

3 select e.deptno,max(e.sal) max_sal,min(e.sal) min_sal

4 from emp e

5 group by e.deptno

6 )

7 select e2.deptno,

8 e2.ename,

9 e2.sal,

10 max_sal,

11 min_sal

12 from emp e2

13 left join tmp1

14 on e2.deptno = tmp1.deptno

15 ORDER BY e2.deptno, e2.sal, e2.ename;

DEPTNO ENAME SAL MAX_SAL MIN_SAL

------ ---------- --------- ---------- ----------

10 MILLER 1300.00 5000 1300

10 CLARK 2450.00 5000 1300

10 KING 5000.00 5000 1300

20 SMITH 800.00 3000 800

20 ADAMS 1100.00 3000 800

20 JONES 2975.00 3000 800

20 FORD 3000.00 3000 800

20 SCOTT 3000.00 3000 800

30 JAMES 950.00 2850 950

30 MARTIN 1250.00 2850 950

30 WARD 1250.00 2850 950

30 TURNER 1500.00 2850 950

30 ALLEN 1600.00 2850 950

30 BLAKE 2850.00 2850 950

14 rows selected

SQL> --排名函数只能进行排名,通过排名可以看出最大和最小薪资,同样需要嵌套临时表来完成此类需求

SQL> --通过keep函数,无需嵌套子查询,代码逻辑更为简单

SQL> SELECT Deptno,

2 Ename,

3 Sal,

4 MIN(Sal) KEEP(DENSE_RANK FIRST ORDER BY sal) OVER(PARTITION BY deptno) max_sal,

5 MAX(sal) KEEP(DENSE_RANK LAST ORDER BY sal) OVER(PARTITION BY deptno) min_sal

6 FROM Emp

7 ORDER BY deptno, sal, ename;

DEPTNO ENAME SAL MAX_SAL MIN_SAL

------ ---------- --------- ---------- ----------

10 MILLER 1300.00 1300 5000

10 CLARK 2450.00 1300 5000

10 KING 5000.00 1300 5000

20 SMITH 800.00 800 3000

20 ADAMS 1100.00 800 3000

20 JONES 2975.00 800 3000

20 FORD 3000.00 800 3000

20 SCOTT 3000.00 800 3000

30 JAMES 950.00 950 2850

30 MARTIN 1250.00 950 2850

30 WARD 1250.00 950 2850

30 TURNER 1500.00 950 2850

30 ALLEN 1600.00 950 2850

30 BLAKE 2850.00 950 2850

14 rows selected

需求:每月的最高和最低销售额对应的区域(如有多个区域按区域列出最小的一个,如某区域某月无销售额则不做统计

SELECT t1.month,

MIN(area) keep(dense_rank FIRST ORDER BY amount DESC) max_area,

MIN(area) keep (dense_rank FIRST ORDER BY amount) min_area

FROM testa t1

GROUP BY t1.month;

SQL> SELECT t1.month,

2 MIN(area) keep(dense_rank FIRST ORDER BY amount DESC) max_area,

3 MIN(area) keep (dense_rank FIRST ORDER BY amount) min_area

4 FROM testa t1

5 GROUP BY t1.month;

MONTH MAX_AREA MIN_AREA

-------------------- -------------------- --------------------

1 北京 广州

2 北京 广州

3 上海 上海

4 上海 上海

二.求累积销售额

需求:求每个区域每个月的销售额以及累积销售额

--传统写法,通过表连接 t1.month >= t2.month 及group语句解决

select t1.area,t1.month,t1.amount,sum(t2.amount) cum_amount

from testa t1

left join testa t2

on t1.area = t2.area

and t1.month >= t2.month

group by t1.area,t1.month,t1.amount

order by t1.area,t1.month;

--通过sum聚合函数与分析函数配合使用,代码更简洁易懂

select t1.area,

t1.month,

t1.amount,

sum(t1.amount) over(partition by t1.area order by month) cum_amount

from testa t1

order by t1.area,t1.month;

SQL> --传统写法,通过表连接 t1.month >= t2.month 及group语句解决

SQL> select t1.area,t1.month,t1.amount,sum(t2.amount) cum_amount

2 from testa t1

3 left join testa t2

4 on t1.area = t2.area

5 and t1.month >= t2.month

6 group by t1.area,t1.month,t1.amount

7 order by t1.area,t1.month;

AREA MONTH AMOUNT CUM_AMOUNT

-------------------- -------------------- ---------- ----------

北京 1 235 235

北京 2 330 565

广州 1 75 75

广州 2 67 142

上海 1 199 199

上海 2 199 398

上海 3 155 1416

上海 4 125 833

8 rows selected

SQL> --通过sum聚合函数与分析函数配合使用,代码更简洁易懂

SQL> select t1.area,

2 t1.month,

3 t1.amount,

4 sum(t1.amount) over(partition by t1.area order by month) cum_amount

5 from testa t1

6 order by t1.area,t1.month;

AREA MONTH AMOUNT CUM_AMOUNT

-------------------- -------------------- ---------- ----------

北京 1 235 235

北京 2 330 565

广州 1 75 75

广州 2 67 142

上海 1 199 199

上海 2 199 398

上海 3 155 708

上海 3 155 708

上海 4 125 833

9 rows selected

正在跳转(iOS交流裙 密码:123)