超级牛皮的oracle的分析函数over(Partition by...) 及开窗函数 - 数据库 - 三路友社论坛 娱乐交友社区论坛 - SNS
返回列表 回复 发帖

超级牛皮的oracle的分析函数over(Partition by...) 及开窗函数

over(Partition by...) 一个超级牛皮的ORACLE特有函数。
天天都用ORACLE,用了快2年了。最近才接触到这个功能强大而灵活的函数。真实惭愧啊!

oracle的分析函数over 及开窗函数
一:分析函数over
Oracle从8.1.6开始提供分析函数,分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是
对于每个组返回多行,而聚合函数对于每个组只返回一行。
下面通过几个例子来说明其应用。                                       
1:统计某商店的营业额。        
     date       sale
     1           20
     2           15
     3           14
     4           18
     5           30
    规则:按天统计:每天都统计前面几天的总额
    得到的结果:
    DATE   SALE       SUM
    ----- -------- ------
    1      20        20           --1天           
    2      15        35           --1天+2天           
    3      14        49           --1天+2天+3天           
    4      18        67            .         
    5      30        97            .
     
2:统计各班成绩第一名的同学信息
    NAME   CLASS S                        
    ----- ----- ----------------------
    fda    1      80                     
    ffd    1      78                     
    dss    1      95                     
    cfe    2      74                     
    gds    2      92                     
    gf     3      99                     
    ddd    3      99                     
    adf    3      45                     
    asdf   3      55                     
    3dd    3      78              
   
    通过:   
    --
    select * from                                                                       
    (                                                                           
    select name,class,s,rank()over(partition by class order by s desc) mm from t2
    )                                                                           
    where mm=1
    --
    得到结果:
    NAME   CLASS S                       MM                                                                                       
    ----- ----- ---------------------- ----------------------
    dss    1      95                      1                     
    gds    2      92                      1                     
    gf     3      99                      1                     
    ddd    3      99                      1         
   
    注意:
    1.在求第一名成绩的时候,不能用row_number(),因为如果同班有两个并列第一,row_number()只返回一个结果         
    2.rank()和dense_rank()的区别是:
      --rank()是跳跃排序,有两个第二名时接下来就是第四名
      --dense_rank()l是连续排序,有两个第二名时仍然跟着第三名
     
     
3.分类统计 (并显示信息)
    A   B   C                     
    -- -- ----------------------
    m   a   2                     
    n   a   3                     
    m   a   2                     
    n   b   2                     
    n   b   1                     
    x   b   3                     
    x   b   2                     
    x   b   4                     
    h   b   3
   select a,c,sum(c)over(partition by a) from t2               
   得到结果:
   A   B   C        SUM(C)OVER(PARTITIONBYA)      
   -- -- ------- ------------------------
   h   b   3        3                        
   m   a   2        4                        
   m   a   2        4                        
   n   a   3        6                        
   n   b   2        6                        
   n   b   1        6                        
   x   b   3        9                        
   x   b   2        9                        
   x   b   4        9                        
  
   如果用sum,group by 则只能得到
   A   SUM(C)                           
   -- ----------------------
   h   3                     
   m   4                     
   n   6                     
   x   9                     
   无法得到B列值      
  
=====
select * from test
数据:
A B C
1 1 1
1 2 2
1 3 3
2 2 5
3 4 6

---将B栏位值相同的对应的C 栏位值加总
select a,b,c, SUM(C) OVER (PARTITION BY B) C_Sum
from test
A B C C_SUM
1 1 1 1
1 2 2 7
2 2 5 7
1 3 3 3
3 4 6 6

---如果不需要已某个栏位的值分割,那就要用 null
eg: 就是将C的栏位值summary 放在每行后面
select a,b,c, SUM(C) OVER (PARTITION BY null) C_Sum
from test
A B C C_SUM
1 1 1 17
1 2 2 17
1 3 3 17
2 2 5 17
3 4 6 17

求个人工资占部门工资的百分比
SQL> select * from salary;
NAME DEPT SAL
---------- ---- -----
a 10 2000
b 10 3000
c 10 5000
d 20 4000
SQL> select name,dept,sal,sal*100/sum(sal) over(partition by dept) percent from salary;
NAME DEPT SAL PERCENT
---------- ---- ----- ----------
a 10 2000 20
b 10 3000 30
c 10 5000 50
d 20 4000 100
二:开窗函数           
      开窗函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化,举例如下:
1:     
   over(order by salary) 按照salary排序进行累计,order by是个默认的开窗函数
   over(partition by deptno)按照部门分区
2:
  over(order by salary range between 5 preceding and 5 following)
   每行对应的数据窗口是之前行幅度值不超过5,之后行幅度值不超过5
   例如:对于以下列
     aa
     1
     2
     2
     2
     3
     4
     5
     6
     7
     9
   
   sum(aa)over(order by aa range between 2 preceding and 2 following)
   得出的结果是
            AA                       SUM
            ---------------------- -------------------------------------------------------
            1                       10                                                      
            2                       14                                                      
            2                       14                                                      
            2                       14                                                      
            3                       18                                                      
            4                       18                                                      
            5                       22                                                      
            6                       18                                                               
            7                       22                                                               
            9                       9                                                                 
            
   就是说,对于aa=5的一行 ,sum为   5-1<=aa<=5+2 的和
   对于aa=2来说 ,sum=1+2+2+2+3+4=14     ;
   又如 对于aa=9 ,9-1<=aa<=9+2 只有9一个数,所以sum=9    ;
              
3:其它:
     over(order by salary rows between 2 preceding and 4 following)
          每行对应的数据窗口是之前2行,之后4行
4:下面三条语句等效:           
     over(order by salary rows between unbounded preceding and unbounded following)
          每行对应的数据窗口是从第一行到最后一行,等效:
     over(order by salary range between unbounded preceding and unbounded following)
           等效
     over(partition by null)

常用的分析函数如下所列:
row_number() over(partition by ... order by ...)
rank() over(partition by ... order by ...)
dense_rank() over(partition by ... order by ...)
count() over(partition by ... order by ...)
max() over(partition by ... order by ...)
min() over(partition by ... order by ...)
sum() over(partition by ... order by ...)
avg() over(partition by ... order by ...)
first_value() over(partition by ... order by ...)
last_value() over(partition by ... order by ...)
lag() over(partition by ... order by ...)
lead() over(partition by ... order by ...)
示例
SQL> select type,qty from test;
TYPE QTY
---------- ----------
1 6
2 9
SQL> select type,qty,to_char(row_number() over(partition by type order by qty))||'/'||to_char(count(*) over(partition by type)) as cnt2 from test;
TYPE QTY CNT2
---------- ---------- ------------
3 1/2
1 6 2/2
2 5 1/3
7 2/3
2 9 3/3
SQL> select * from test;
---------- -------------------------------------------------
1 11111
2 22222
3 33333
4 44444
SQL> select t.id,mc,to_char(b.rn)||'/'||t.id)e
2 from test t,
(select rownum rn from (select max(to_number(id)) mid from test) connect by rownum <=mid ))L
4 where b.rn<=to_number(t.id)
order by id
ID MC TO_CHAR(B.RN)||'/'||T.ID
--------- -------------------------------------------------- ---------------------------------------------------
1 11111 1/1
2 22222 1/2
2 22222 2/2
3 33333 1/3
3 33333 2/3
3 33333 3/3
44444 1/4 44444 2/4
4 44444 3/4CNOUG4 44444 4/4
10 rows selected
*******************************************************************
关于partition by
这些都是分析函数,好像是8.0以后才有的 row_number()和rownum差不多,功能更强一点(可以在各个分组内从1开时排序) rank()是跳跃排序,有两个第二名时接下来就是第四名(同样是在各个分组内) dense_rank()l是连续排序,有两个第二名时仍然跟着第三名。相比之下row_number是没有重复值的 lag(arg1,arg2,arg3): arg1是从其他行返回的表达式 arg2是希望检索的当前行分区的偏移量。是一个正的偏移量,时一个往回检索以前的行的数目。 arg3是在arg2表示的数目超出了分组的范围时返回的值。
1.
select deptno,row_number() over(partition by deptno order by sal) from emp order by deptno;
2.
select deptno,rank() over (partition by deptno order by sal) from emp order by deptno;
3.
select deptno,dense_rank() over(partition by deptno order by sal) from emp order by deptno;
4.
select deptno,ename,sal,lag(ename,1,null) over(partition by deptno order by ename) from emp ord er by deptno;
5.
select deptno,ename,sal,lag(ename,2,'example') over(partition by deptno order by ename) from em p
order by deptno;
6.
select deptno, sal,sum(sal) over(partition by deptno) from emp;--每行记录后都有总计值  select deptno, sum(sal) from emp group by deptno;
7. 求每个部门的平均工资以及每个人与所在部门的工资差额
select deptno,ename,sal ,
     round(avg(sal) over(partition by deptno)) as dept_avg_sal,
     round(sal-avg(sal) over(partition by deptno)) as dept_sal_diff
from emp;
姜文给发哥和优哥的信

致发哥发嫂:易发棋牌

香江匆晤,所谈甚欢。新片故事,随信奉上。故事锤炼数载,脚本即将出炉,人物之妙,惊古烁今,片中,兄将分身异术,同饰真伪,定为兄之演技提供辽阔空间,创影林之美谈。

发哥盛名,中外有识;为艺厚道,技盖群雄。此角色必助发哥携已获之辉煌,跨更高之巅峰。

新片旨在造中国之西部黑帮电影。诙谐荒诞,凌厉跌宕。昔有Leone(莱昂)之通心意粉牛仔戏,今有吾辈之麻辣袍哥西部片。发哥之角,既有曹孟德之雄,又具周公瑾之英,且常自诩诸葛孔明。回肠荡气,出人意表,发哥出手,定收放自如,出神入化,万千fans,翘首期待!谁敢做他人之想?!

新片除愚弟之外,尚有葛优兄加盟。真可谓:三江汇处有富域,三雄鼎力看妙篇。壮哉美哉!

放眼中原,勃勃生机;星汉灿烂,交汇其里。闻听发嫂令下,发哥将至,上下同仁,无不振奋!

早春二月,岭南草长;杂花生树,群鸥竟飞。适此惠风和畅之日,诚邀阁下共成美事。书不尽言,晤面详之。

Kindest regard, 易发棋牌 真钱斗地主真钱扎金花  


姜文谨启

附 致葛优书

易发棋牌
优优吾兄:

壶口一别,竟有二七。春风秋月,杨柳依依。虽谋面不勤,却心存惦记!吾兄凡新作问世,愚弟必争先读之。兄之身手炉火纯青,每令愚弟嚎啕大悦。才惊四海,誉享中外。喜甚幸甚!

新片筹备井然,故事随信奉上。精华仍在提炼,脚本即将出膛。人物之妙,惊古烁今。且为兄之发挥,提供辽阔疆场。

深信此角,必能助兄,继往开来,再创辉煌。届时亿万女粉,翻江倒海,抛家舍业,秋波明荡,不亦艳乎?

纵使,狡兔八窟,数易家宅,亦难阻。拥趸之风暴,优党之痴狂!直落得,隐身天涯,革面洗肠,不亦喜乎?

吾兄片中虽无艳星共枕,但有愚弟陪床。醉眠秋共被,携手日同行。耳鬓厮磨,却非断臂,不亦骚乎?

新片除却愚弟之外,尚有发哥亮相。左右拱卫,冬暖夏凉。不亦乐乎?

喜骚艳乐,应有尽有,揽得雎 鸠淑女,亮亮君子何求?闻听吾兄将至,同仁上下,无不开颜。须眉脚扑朔,巾帼眼迷离。鼓瑟鼓簧为兄弟,磨刀霍霍向猪羊。

呦呦鹿鸣,食野之苹,悠悠我心,青青子衿。恰逢瑞雪早春,恕愚弟威逼利诱。皆因爱之心切,盼之心痒。江东渭北,春树暮云。书不尽言,晤面详之。

草此即问,全家均安。

愚弟姜文

两份信,彰显了姜文超凡脱俗的才气。

易发棋牌 祝《让子弹飞》票房满满,收获多多。

更多精彩尽在,大发扑克
返回列表