ITPub博客

首页 > 数据库 > Oracle > Expert 101 Oracle 分析函数

Expert 101 Oracle 分析函数

原创 Oracle 作者:blue_prince 时间:2000-01-01 00:00:12 0 删除 编辑

一、 一个查询例子:[php]

SQL> break on deptno skip 1

SQL> select ename,deptno,sal,

2 sum(sal) over (order by deptno,ename) running_total,

3 sum(sal) over (partition by deptno order by ename) department_total,

4 row_number() over (partition by deptno order by ename) seq

5 from emp;[/php]

[@more@]

[php]ENAME DEPTNO SAL RUNNING_TOTAL DEPARTMENT_TOTAL SEQ

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

CLARK 10 2450 2450 2450 1

KING 5000 7450 7450 2

MILLER 1300 8750 8750 3

FORD 20 3000 11750 3000 1

JONES 2975 14725 5975 2

SMITH 800 15525 6775 3

ALLEN 30 1600 17125 1600 1

BLAKE 2850 19975 4450 2

JAMES 950 20925 5400 3

MARTIN 1250 22175 6650 4

TURNER 1500 23675 8150 5

WARD 1250 24925 9400 6

二、测试分析函数与传统查询的效率比较:

SQL> create table t

2 as

3 select object_name ename,

4 mod(object_id,50) deptno,

5 object_id sal

6 from all_objects

7 where rownum<=1000

8 /

Table created.

SQL> create index idx_t on t(deptno,ename);

Index created.

SQL> select ename,deptno,sal,

2 sum(sal) over (order by deptno,ename) running_total,

3 sum(sal) over (partition by deptno order by ename) department_total,

4 row_number() over (partition by deptno order by ename) seq

5 from t emp

6 order by deptno,ename

7 /

1000 rows selected.

Elapsed: 00:00:00.03

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 WINDOW (BUFFER)

2 1 TABLE ACCESS (BY INDEX ROWID) OF 'T'

3 2 INDEX (FULL SCAN) OF 'IDX_T' (NON-UNIQUE)

Statistics

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

0 recursive calls

0 db block gets

231 consistent gets

5 physical reads

0 redo size

49242 bytes sent via SQL*Net to client

1229 bytes received via SQL*Net from client

68 SQL*Net roundtrips to/from client

1 sorts (memory)

0 sorts (disk)

1000 rows processed

SQL> select ename, deptno, sal,

2 (select sum(sal)

3 from t e2

4 where e2.deptno < emp.deptno

5 or (e2.deptno = emp.deptno and e2.ename <= emp.ename ))

6 running_total,

7 (select sum(sal)

8 from t e3

9 where e3.deptno = emp.deptno

10 and e3.ename <= emp.ename)

11 department_total,

12 (select count(ename)

13 from t e3

14 where e3.deptno = emp.deptno

15 and e3.ename <= emp.ename)

16 seq

17 from t emp

18 order by deptno, ename

19 /

1000 rows selected.

Elapsed: 00:00:01.02

Execution Plan

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

0 SELECT STATEMENT Optimizer=CHOOSE

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T'

2 1 INDEX (FULL SCAN) OF 'IDX_T' (NON-UNIQUE)

Statistics

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

0 recursive calls

0 db block gets

119344 consistent gets

0 physical reads

0 redo size

49242 bytes sent via SQL*Net to client

1229 bytes received via SQL*Net from client

68 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1000 rows processed

可以看到,用分析函数全部执行了0.03秒,发生了231个逻辑IO。没有利用分析函数的则执行了将近1.02秒,发生高达119244个逻辑IO。有没利用分析函数的效率是不言而喻的。

三、分析函数语法:

FUNCTION_NAME(,,…)

OVER

( )

order by 区别:

SQL> select ename,sal,avg(sal) over(order by ename)

2 from emp

3 /

ENAME SAL AVG(SAL)OVER(ORDERBYENAME)

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

ALLEN 1600 1600

BLAKE 2850 2225

CLARK 2450 2300

FORD 3000 2475

JAMES 950 2170

JONES 2975 2304.16667

KING 5000 2689.28571

MARTIN 1250 2509.375

MILLER 1300 2375

SMITH 800 2217.5

TURNER 1500 2152.27273

WARD 1250 2077.08333

12 rows selected.

order by的利用当前行及其之前的行进行统计。

Elapsed: 00:00:00.00

SQL> select ename,sal,avg(sal) over()

2 from emp

3 /

ENAME SAL AVG(SAL)OVER()

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

SMITH 800 2077.08333

ALLEN 1600 2077.08333

WARD 1250 2077.08333

JONES 2975 2077.08333

MARTIN 1250 2077.08333

BLAKE 2850 2077.08333

CLARK 2450 2077.08333

KING 5000 2077.08333

TURNER 1500 2077.08333

JAMES 950 2077.08333

FORD 3000 2077.08333

MILLER 1300 2077.08333

12 rows selected.

order by子句的利用全部值进行统计。

1 select ename, deptno,sal,

2 sum(sal) over (order by ename, deptno) sum_ename_deptno,

3 sum(sal) over (order by deptno, ename) sum_deptno_ename

4 from emp

5* order by ename, deptno

SQL> /

ENAME DEPTNO SAL SUM_ENAME_DEPTNO SUM_DEPTNO_ENAME

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

ALLEN 30 1600 1600 17125

BLAKE 30 2850 4450 19975

CLARK 10 2450 6900 2450

FORD 20 3000 9900 11750

JAMES 30 950 10850 20925

JONES 20 2975 13825 14725

KING 10 5000 18825 7450

MARTIN 30 1250 20075 22175

MILLER 10 1300 21375 8750

SMITH 20 800 22175 15525

TURNER 30 1500 23675 23675

WARD 30 1250 24925 24925

第一行ename为ALLEN,他的工具为1600,故总计工资也为1600。而他的deptno为30,根据DEPTNO排序计算的话,必须包括从10至当前行的值,故为17125。

1 select ename, deptno,sal,

2 sum(sal) over (order by ename, deptno) sum_ename_deptno,

3 sum(sal) over (order by deptno, ename) sum_deptno_ename

4 from emp

5* order by deptno,ename

SQL> /

ENAME DEPTNO SAL SUM_ENAME_DEPTNO SUM_DEPTNO_ENAME

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

CLARK 10 2450 6900 2450

KING 10 5000 18825 7450

MILLER 10 1300 21375 8750

FORD 20 3000 9900 11750

JONES 20 2975 13825 14725

SMITH 20 800 22175 15525

ALLEN 30 1600 1600 17125

BLAKE 30 2850 4450 19975

JAMES 30 950 10850 20925

MARTIN 30 1250 20075 22175

TURNER 30 1500 23675 23675

WARD 30 1250 24925 24925

5、Windowing子句:给出一个定义变化或固定的数据窗口方法,分析函数将对这些数据进行操作。必须使用order by子句。

1、)ROWS窗口:包括在窗口中的行的物理数。

部门前两行雇员与当前行工资总和:

1 select deptno,ename,sal ,

2 sum(sal) over (partition by deptno order by ename rows 2 preceding)

3 sliending_total

4 from emp

5* order by deptno,ename

SQL> /

DEPTNO ENAME SAL SLIENDING_TOTAL

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

10 CLARK 2450 2450

KING 5000 7450

MILLER 1300 8750

20 FORD 3000 3000

JONES 2975 5975

SMITH 800 6775

30 ALLEN 1600 1600

BLAKE 2850 4450

JAMES 950 5400

MARTIN 1250 5050

TURNER 1500 3700

WARD 1250 4000

hiredate升序排序,提取包括当前行在内及其前5行的第一个员工信息:

SQL> select ename,hiredate,sal,

2 first_value(ename) over

3 (order by hiredate rows 5 preceding) ename_prec,

4 first_value(hiredate) over

5 (order by hiredate rows 5 preceding) hiredate_prec

6 from emp

7 order by hiredate

8 /

ENAME HIREDATE SAL ENAME_PREC HIREDATE_

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

SMITH 17-DEC-80 800.00 SMITH 17-DEC-80

ALLEN 20-FEB-81 1600.00 SMITH 17-DEC-80

WARD 22-FEB-81 1250.00 SMITH 17-DEC-80

JONES 02-APR-81 2975.00 SMITH 17-DEC-80

BLAKE 01-MAY-81 2850.00 SMITH 17-DEC-80

CLARK 09-JUN-81 2450.00 SMITH 17-DEC-80

TURNER 08-SEP-81 1500.00 ALLEN 20-FEB-81

MARTIN 28-SEP-81 1250.00 WARD 22-FEB-81

KING 17-NOV-81 5000.00 JONES 02-APR-81

JAMES 03-DEC-81 950.00 BLAKE 01-MAY-81

FORD 03-DEC-81 3000.00 CLARK 09-JUN-81

MILLER 23-JAN-82 1300.00 TURNER 08-SEP-81

hiredatet降序排序,包括当前行及其前5行求值:

SQL> select ename,hiredate,sal,

2 first_value(ename) over

3 (order by hiredate desc rows 5 preceding) ename_prec,

4 first_value(hiredate) over

5 (order by hiredate desc rows 5 preceding) hiredate_prec

6 from emp

7 order by hiredate desc

8 /

ENAME HIREDATE SAL ENAME_PREC HIREDATE_

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

MILLER 23-JAN-82 1300.00 MILLER 23-JAN-82

JAMES 03-DEC-81 950.00 MILLER 23-JAN-82

FORD 03-DEC-81 3000.00 MILLER 23-JAN-82

KING 17-NOV-81 5000.00 MILLER 23-JAN-82

MARTIN 28-SEP-81 1250.00 MILLER 23-JAN-82

TURNER 08-SEP-81 1500.00 MILLER 23-JAN-82

CLARK 09-JUN-81 2450.00 JAMES 03-DEC-81

BLAKE 01-MAY-81 2850.00 FORD 03-DEC-81

JONES 02-APR-81 2975.00 KING 17-NOV-81

WARD 22-FEB-81 1250.00 MARTIN 28-SEP-81

ALLEN 20-FEB-81 1600.00 TURNER 08-SEP-81

SMITH 17-DEC-80 800.00 CLARK 09-JUN-81

Hiredate升序或降序排序后,当前行之前5行求平均工资及其统计行数:

SQL> select ename,hiredate,sal,

2 avg(sal) over

3 (order by hiredate asc rows 5 preceding) before_avg,

4 count(*) over

5 (order by hiredate asc rows 5 preceding) before_obs,

6 avg(sal) over

7 (order by hiredate desc rows 5 preceding) after_avg,

8 count(*) over

9 (order by hiredate desc rows 5 preceding) after_obs

10 from emp

11 order by hiredate

12 /

ENAME HIREDATE SAL BEFORE_AVG BEFORE_OBS AFTER_AVG AFTER_OBS

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

SMITH 17-DEC-80 800.00 800.00 1.00 1987.50 6.00

ALLEN 20-FEB-81 1600.00 1200.00 2.00 2104.17 6.00

WARD 22-FEB-81 1250.00 1216.67 3.00 2045.83 6.00

JONES 02-APR-81 2975.00 1656.25 4.00 2670.83 6.00

BLAKE 01-MAY-81 2850.00 1895.00 5.00 2675.00 6.00

CLARK 09-JUN-81 2450.00 1987.50 6.00 2358.33 6.00

TURNER 08-SEP-81 1500.00 2104.17 6.00 2166.67 6.00

MARTIN 28-SEP-81 1250.00 2045.83 6.00 2300.00 5.00

KING 17-NOV-81 5000.00 2670.83 6.00 2562.50 4.00

JAMES 03-DEC-81 950.00 2333.33 6.00 1125.00 2.00

FORD 03-DEC-81 3000.00 2358.33 6.00 1750.00 3.00

MILLER 23-JAN-82 1300.00 2166.67 6.00 1300.00 1.00

2、)Range窗口:根据where条件将行集中在一起。如range N preceding,将在组内拥有当前行以前N行的组合。只能用于数字和日期的数据类型比较。

例:按hiredate升序排序,求每一行前100天之内的第一个员工及对应入职日期(升序时,由于是求当前行之前范围的值,因此必须是日期减去100):

SQL> select ename,sal,hiredate,hiredate-100,

2 first_value(ename)

3 over

[/php]

4

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/60857/viewspace-807614/,如需转载,请注明出处,否则将追究法律责任。

上一篇: 一次惨痛的教训
请登录后发表评论 登录
全部评论

注册时间:2007-12-23

  • 博文量
    92
  • 访问量
    2217843