Oracle分析函数总结(3)- 数值分布 - cume_dist,percent_rank,ntile,percentile_disc,percentile_cont,ratio_to_report

时间:2024-10-03 07:11:00

分析函数的基本概念和语法 -> /fw0124/article/details/7842039

下面这些函数计算某个值在一组有序数据中的累计分布(cumulative distribution)

1) cume_dist()
计算结果为相对位置/总行数。返回值(0,1]。
例如在一个5行的组中,返回的累计分布值为0.2,0.4,0.6,0.8,1.0;
注意对于重复行,计算时取重复行中的最后一行的位置。

a)作为聚合函数的用法
语法:cume_dist(expr) with group (order by exp)
cume_dist()用参数中的指定的数据构造一条假定的数据并插入到现存行中,
然后计算这条假定数据在所有行中的相对位置。
例如下面的查询中,emp中总共有14行数据,
假定的数据(deptno=20,sal=4000)会插入到第9行,
因此相对位置 9/(14+1)=0.6。

  1. tony@ORA11GR2> select cume_dist(20,4000)
  2. 2 within group (order by deptno, sal) cume_dist
  3. 3 from emp;
  4. CUME_DIST
  5. ----------
  6. .6


b)作为分析函数的用法
语法:cume_dist() over([partition_clause] order_by_clause)
例如计算每个人在本部门按照薪水排列中的相对位置。

  1. tony@ORA11GR2> select ename, sal, deptno,
  2. 2 cume_dist() over(partition by deptno order by sal) cume_dist
  3. 3 from emp;
  4. ENAME SAL DEPTNO CUME_DIST
  5. -------------------- ---------- ---------- ----------
  6. MILLER 1300 10 .333333333
  7. CLARK 2450 10 .666666667
  8. KING 5002 10 1
  9. SMITH 800 20 .2
  10. ADAMS 1100 20 .4
  11. JONES 2975 20 .6
  12. SCOTT 3000 20 1
  13. FORD 3000 20 1
  14. JAMES 950 30 .166666667
  15. MARTIN 1250 30 .5
  16. WARD 1250 30 .5
  17. TURNER 1500 30 .666666667
  18. ALLEN 1600 30 .833333333
  19. BLAKE 2850 30 1
  20. 已选择14行。


2) percent_rank()
和cume_dist的不同点在于计算分布结果的方法。
计算方法为 (相对位置-1)/(总行数-1),
因此第一行的结果为0。返回值[0,1]。
例如在一个5行的组中,返回的累计分布值为0,0.25,0.5,0.75,1.0;
注意对于重复行,计算时取重复行中的第一行的位置。

a)作为聚合函数的用法
语法:percent_rank(expr) with group (order by exp)
下面的例子中,类似cume_dist,假定数据(deptno=20,sal=4000)会插入到第9行,
计算相对位置 (9-1)/((14+1)-1)=0.57

  1. tony@ORA11GR2> select percent_rank(20,4000)
  2. 2 within group (order by deptno, sal) percent_rank
  3. 3 from emp;
  4. PERCENT_RANK
  5. ------------
  6. .571428571


b)作为分析函数的用法
语法: percent_rank() over([partition_clause] order_by_clause)
例如计算每个人在本部门按照薪水排列中的相对位置。

  1. tony@ORA11GR2> select ename, sal, deptno,
  2. 2 percent_rank() over(partition by deptno order by sal) percent_rank
  3. 3 from emp;
  4. ENAME SAL DEPTNO PERCENT_RANK
  5. -------------------- ---------- ---------- ------------
  6. MILLER 1300 10 0
  7. CLARK 2450 10 .5
  8. KING 5002 10 1
  9. SMITH 800 20 0
  10. ADAMS 1100 20 .25
  11. JONES 2975 20 .5
  12. SCOTT 3000 20 .75
  13. FORD 3000 20 .75
  14. JAMES 950 30 0
  15. MARTIN 1250 30 .2
  16. WARD 1250 30 .2
  17. TURNER 1500 30 .6
  18. ALLEN 1600 30 .8
  19. BLAKE 2850 30 1
  20. 已选择14行。


3) percentile_disc()
返回一个与输入的分布百分比值相对应的数据值,
分布百分比的计算方法同函数CUME_DIST(),
如果没有正好对应的数据值,就取大于该分布值的下一个值。

a)作为聚合函数的用法
语法: percentile_disc(expr) with group (order by expr)
例如,查询各部门中薪水分布处于40%位置的人的薪水。

  1. tony@ORA11GR2> select deptno,
  2. 2 percentile_disc(0.4) within group (order by sal) percentile_disc
  3. 3 from emp group by deptno;
  4. DEPTNO PERCENTILE_DISC
  5. ---------- ---------------
  6. 10 2450
  7. 20 1100
  8. 30 1250

2)作为分析函数的用法
语法:percentile_disc(expr) with group (order by expr) over([partition_clause])
例如,查询各部门中薪水分布处于40%位置的人的薪水。注意和cume_dist()的输出结果作对照。

  1. tony@ORA11GR2> select ename, sal, deptno,
  2. 2 cume_dist() over(partition by deptno order by sal) cume_dist,
  3. 3 percentile_disc(0.4) within group (order by sal)
  4. 4 over(partition by deptno) percentile_disc
  5. 5 from emp;
  6. ENAME SAL DEPTNO CUME_DIST PERCENTILE_DISC
  7. -------------------- ---------- ---------- ---------- ---------------
  8. MILLER 1300 10 .333333333 2450
  9. CLARK 2450 10 .666666667 2450
  10. KING 5002 10 1 2450
  11. SMITH 800 20 .2 1100
  12. ADAMS 1100 20 .4 1100
  13. JONES 2975 20 .6 1100
  14. SCOTT 3000 20 1 1100
  15. FORD 3000 20 1 1100
  16. JAMES 950 30 .166666667 1250
  17. MARTIN 1250 30 .5 1250
  18. WARD 1250 30 .5 1250
  19. TURNER 1500 30 .666666667 1250
  20. ALLEN 1600 30 .833333333 1250
  21. BLAKE 2850 30 1 1250
  22. 已选择14行。


4) percentile_cont()
返回一个与输入的分布百分比值相对应的数据值,分布百分比的计算方法同函数PERCENT_RANK(),
如果没有正好对应的数据值,就通过下面算法来得到值:
RN = 1+ (P*(N-1)) 其中P是输入的分布百分比值,N是组内的行数
CRN = CEIL(RN) FRN = FLOOR(RN)
  If (CRN = FRN = RN) then the result is
    (value of expression from row at RN)
  Otherwise the result is
    (CRN - RN) * (value of expression for row at FRN) +
    (RN - FRN) * (value of expression for row at CRN)
上面的算法比较难理解,实际上可以看作X轴上最小坐标0,最大坐标(行数-1),
先根据输入百分比找到对应的X轴坐标,然后按比例计算对应的数值。

a)作为聚合函数的用法
语法percentile_cont(expr) with group (order by expr)
下面的例子中,部门号30中薪水处于50%位置的数额计算方法:
RN=1+(0.5*(6-1))=3.5;CRN=4;FRN=3;
结果=(4-3.5)*1250+(3.5-3)*1500=1375

  1. tony@ORA11GR2> select deptno,
  2. 2 percentile_cont(0.5) within group (order by sal) percentile_cont
  3. 3 from emp group by deptno;
  4. DEPTNO PERCENTILE_CONT
  5. ---------- ---------------
  6. 10 2450
  7. 20 2975
  8. 30 1375


b)作为分析函数的用法
语法:percentile_cont(expr) with group (order by expr) over([partition_clause])
例如,计算各部门中薪水处于50%位置的薪水数额,注意和percent_rank()的输出结果作对照。

  1. tony@ORA11GR2> select ename, sal, deptno,
  2. 2 percent_rank() over(partition by deptno order by sal) percent_rank,
  3. 3 percentile_cont(0.5) within group (order by sal)
  4. 4 over(partition by deptno) percentile_cont
  5. 5 from emp;
  6. ENAME SAL DEPTNO PERCENT_RANK PERCENTILE_CONT
  7. -------------------- ---------- ---------- ------------ ---------------
  8. MILLER 1300 10 0 2450
  9. CLARK 2450 10 .5 2450
  10. KING 5002 10 1 2450
  11. SMITH 800 20 0 2975
  12. ADAMS 1100 20 .25 2975
  13. JONES 2975 20 .5 2975
  14. SCOTT 3000 20 .75 2975
  15. FORD 3000 20 .75 2975
  16. JAMES 950 30 0 1375
  17. MARTIN 1250 30 .2 1375
  18. WARD 1250 30 .2 1375
  19. TURNER 1500 30 .6 1375
  20. ALLEN 1600 30 .8 1375
  21. BLAKE 2850 30 1 1375
  22. 已选择14行。


5) ntile()
只能用作分析函数。
语法: ntile(expr) over([partition_clause] order_by_clause)
可以看作是把有序的数据集合平均分配到expr指定的数量的桶中,将桶号分配给每一行。
如果不能平均分配,则较小桶号的桶分配额外的行,并且各个桶中能放的行数最多相差1。
例如如果桶的数量为4,一共有6行,则:
1号桶:1行,2行;
2号桶:3行,4行;
3号桶:5行;
4号桶:6行;
例如,NTILE列返回每一行所应该被分配的桶号。

  1. tony@ORA11GR2> select ename, sal, deptno,
  2. 2 ntile(4) over(partition by deptno order by sal) ntile
  3. 3 from emp;
  4. ENAME SAL DEPTNO NTILE
  5. -------------------- ---------- ---------- ----------
  6. MILLER 1300 10 1
  7. CLARK 2450 10 2
  8. KING 5002 10 3
  9. SMITH 800 20 1
  10. ADAMS 1100 20 1
  11. JONES 2975 20 2
  12. SCOTT 3000 20 3
  13. FORD 3000 20 4
  14. JAMES 950 30 1
  15. MARTIN 1250 30 1
  16. WARD 1250 30 2
  17. TURNER 1500 30 2
  18. ALLEN 1600 30 3
  19. BLAKE 2850 30 4
  20. 已选择14行。


6) ratio_to_report()
计算当前行的数值在分组中所有行的数值总和中所占的比例。
语法:ratio_to_report(expr) over([partition_clause])
例如,计算每个人的薪水在部门薪水总额中的比例。

  1. tony@ORA11GR2> select ename, sal, deptno,
  2. 2 sum(sal) over(partition by deptno) dept_sal_sum,
  3. 3 ratio_to_report(sal) over(partition by deptno) ratio_to_report
  4. 4 from emp;
  5. ENAME SAL DEPTNO DEPT_SAL_SUM RATIO_TO_REPORT
  6. -------------------- ---------- ---------- ------------ ---------------
  7. CLARK 2450 10 8752 .279936015
  8. KING 5002 10 8752 .571526508
  9. MILLER 1300 10 8752 .148537477
  10. JONES 2975 20 10875 .273563218
  11. FORD 3000 20 10875 .275862069
  12. ADAMS 1100 20 10875 .101149425
  13. SMITH 800 20 10875 .073563218
  14. SCOTT 3000 20 10875 .275862069
  15. WARD 1250 30 9400 .132978723
  16. TURNER 1500 30 9400 .159574468
  17. ALLEN 1600 30 9400 .170212766
  18. JAMES 950 30 9400 .10106383
  19. BLAKE 2850 30 9400 .303191489
  20. MARTIN 1250 30 9400 .132978723
  21. 已选择14行。