over partition by与group by

over partition by与group by 的区别

http://www.cnblogs.com/scottpei/archive/2012/02/16/2353718.html

今天看到一个老兄的问题,
大概如下:
查询出部门的最低工资的userid 号
表结构: 

D号      工资      部门
userid salary   dept
1      2000      1
2      1000      1
3      500       2
4      1000      2 

有一个高人给出了一种答案:
SELECT MIN (salary) OVER (PARTITION BY dept ) salary, dept
FROM ss 

运行后得到:
1000 1
1000 1
500 2
500 2
楼主那位老兄一看觉得很高深。大叹真是高人阿~
我也觉得这位老兄实在是高啊。 

但我仔细研究一下发现那位老兄对PARTITION BY的用法理解并不深刻。并没有解决楼主的问题。
大家请看我修改后的语句
SELECT userid,salary,dept,MIN (salary) OVER (PARTITION BY dept ) salary
FROM ss 

运行后的结果:
userid   salary dept      MIN (salary) OVER (PARTITION BY dept )
1 2000 1 1000
2 1000 1 1000
3 500 2 500
4 1000 2 500 

大家看出端倪了吧。
高深的未必适合。 

一下是我给出的答案:
SELECT * FROM SS
INNER JOIN (SELECT MIN(SALARY) AS SALARY, DEPT FROM SS GROUP BY DEPT) SS2
USING(SALARY,DEPT) 

运行后的结果:
salary dept     userid
1000 1 2
500 2 3 

由此我想到总结一下group by和partition by的用法
group by是对检索结果的保留行进行单纯分组,一般总爱和聚合函数一块用例如AVG(),COUNT(),max(),main()等一块用。 

partition by虽然也具有分组功能,但同时也具有其他的功能。
它属于oracle的分析用函数。
借用一个勤快人的数据说明一下: 

sum()   over   (PARTITION   BY   ...)   是一个分析函数。   他执行的效果跟普通的sum   ...group   by   ...不一样,它计算组中表达式的累积和,而不是简单的和。   

表a,内容如下:
B C D
02 02 1
02 03 2
02 04 3
02 05 4
02 01 5
02 06 6
02 07 7
02 03 5
02 02 12
02 01 2
02 01 23   

select   b,c,sum(d)   e   from   a   group   by   b,c
得到:
B C E
02 01 30
02 02 13
02 03 7
02 04 3
02 05 4
02 06 6
02 07 7   

而使用分析函数得到的结果是:
SELECT   b,   c,   d,   SUM(d)   OVER(PARTITION   BY   b,c   ORDER   BY   d)   e   FROM   a
B C E
02 01 2
02 01 7
02 01 30
02 02 1
02 02 13
02 03 2
02 03 7
02 04 3
02 05 4
02 06 6
02 07 7
结果不一样,这样看还不是很清楚,我们把d的内容也显示出来就更清楚了:
SELECT   b,   c,   d,SUM(d)   OVER(PARTITION   BY   b,c   ORDER   BY   d)   e   FROM   a
B C D E
02 01 2 2                     d=2,sum(d)=2
02 01 5 7                     d=5,sum(d)=7
02 01 23 30                   d=23,sum(d)=30
02 02 1 1                     c值不同,重新累计
02 02 12 13
02 03 2 2
02 03 5 7
02 04 3 3
02 05 4 4
02 06 6 6
02 07 7 7

http://www.cnblogs.com/lanzi/archive/2010/10/26/1861338.html

OVER(PARTITION BY)函数介绍

开窗函数

Oracle从8.1.6开始提供分析函数,分析函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是:对于每个组返回多行,而聚合函数对于每个组只返回一行。

开窗函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化,举例如下:

1:over后的写法:

over(order by salary) 按照salary排序进行累计,order by是个默认的开窗函数    over(partition by deptno)按照部门分区

over(partition by deptno order by salary)

2:开窗的窗口范围: over(order by salary range between 5 preceding and 5 following):窗口范围为当前行数据幅度减5加5后的范围内的。

举例:

--sum(s)over(order by s range between 2 preceding and 2 following) 表示加2或2的范围内的求和

select name,class,s, sum(s)over(order by s range between 2 preceding and 2 following) mm from t2 adf        3        45        45  --45加2减2即43到47,但是s在这个范围内只有45 asdf       3        55        55 cfe        2        74        74 3dd        3        78        158 --78在76到80范围内有78,80,求和得158 fda        1        80        158 gds        2        92        92 ffd        1        95        190 dss        1        95        190 ddd        3        99        198

gf         3        99        198

over(order by salary rows between 5 preceding and 5 following):窗口范围为当前行前后各移动5行。

举例:

--sum(s)over(order by s rows between 2 preceding and 2 following)表示在上下两行之间的范围内 select name,class,s, sum(s)over(order by s rows between 2 preceding and 2 following) mm from t2 adf        3        45        174  (45+55+74=174) asdf       3        55        252   (45+55+74+78=252) cfe        2        74        332    (74+55+45+78+80=332) 3dd        3        78        379    (78+74+55+80+92=379) fda        1        80        419 gds        2        92        440 ffd        1        95        461 dss        1        95        480 ddd        3        99        388 gf         3        99        293

over(order by salary range between unbounded preceding and unbounded following)或者

over(order by salary rows between unbounded preceding and unbounded following):窗口不做限制

3、与over函数结合的几个函数介绍

row_number()over()、rank()over()和dense_rank()over()函数的使用

下面以班级成绩表t2来说明其应用

t2表信息如下: cfe        2        74 dss        1        95 ffd        1        95 fda        1        80 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; 得到的结果是: dss        1        95        1 ffd        1        95        1 gds        2        92        1 gf         3        99        1 ddd        3        99        1
注意:     1.在求第一名成绩的时候,不能用row_number(),因为如果同班有两个并列第一,row_number()只返回一个结果; select * from                                                                          (                                                                               select name,class,s,row_number()over(partition by class order by s desc) mm from t2     )                                                                               where mm=1; 1        95        1  --95有两名但是只显示一个 2        92        1 3        99        1 --99有两名但也只显示一个
    2.rank()和dense_rank()可以将所有的都查找出来: 如上可以看到采用rank可以将并列第一名的都查找出来;      rank()和dense_rank()区别:      --rank()是跳跃排序,有两个第二名时接下来就是第四名; select name,class,s,rank()over(partition by class order by s desc) mm from t2 dss        1        95        1 ffd        1        95        1 fda        1        80        3 --直接就跳到了第三 gds        2        92        1 cfe        2        74        2 gf         3        99        1 ddd        3        99        1 3dd        3        78        3 asdf       3        55        4 adf        3        45        5      --dense_rank()l是连续排序,有两个第二名时仍然跟着第三名 select name,class,s,dense_rank()over(partition by class order by s desc) mm from t2 dss        1        95        1 ffd        1        95        1 fda        1        80        2 --连续排序(仍为2) gds        2        92        1 cfe        2        74        2 gf         3        99        1 ddd        3        99        1 3dd        3        78        2 asdf       3        55        3 adf        3        45        4
--sum()over()的使用
select name,class,s, sum(s)over(partition by class order by s desc) mm from t2 --根据班级进行分数求和 dss        1        95        190  --由于两个95都是第一名,所以累加时是两个第一名的相加 ffd        1        95        190 fda        1        80        270  --第一名加上第二名的 gds        2        92        92 cfe        2        74        166 gf         3        99        198 ddd        3        99        198 3dd        3        78        276 asdf       3        55        331 adf        3        45        376

first_value() over()和last_value() over()的使用  

--找出这三条电路每条电路的第一条记录类型和最后一条记录类型

SELECT opr_id,res_type,        first_value(res_type) over(PARTITION BY opr_id ORDER BY res_type) low,        last_value(res_type) over(PARTITION BY opr_id ORDER BY res_type rows BETWEEN unbounded preceding AND unbounded following) high   FROM rm_circuit_route WHERE opr_id IN (‘000100190000000000021311‘,‘000100190000000000021355‘,‘000100190000000000021339‘)  ORDER BY opr_id;

注:rows BETWEEN unbounded preceding AND unbounded following 的使用

--取last_value时不使用rows BETWEEN unbounded preceding AND unbounded following的结果

SELECT opr_id,res_type,        first_value(res_type) over(PARTITION BY opr_id ORDER BY res_type) low,        last_value(res_type) over(PARTITION BY opr_id ORDER BY res_type) high   FROM rm_circuit_route  WHERE opr_id IN (‘000100190000000000021311‘,‘000100190000000000021355‘,‘000100190000000000021339‘)  ORDER BY opr_id;

如下图可以看到,如果不使用

rows BETWEEN unbounded preceding AND unbounded following,取出的last_value由于与res_type进行进行排列,因此取出的电路的最后一行记录的类型就不是按照电路的范围提取了,而是以res_type为范围进行提取了。

 

 

在first_value和last_value中ignore nulls的使用

数据如下:

取出该电路的第一条记录,加上ignore nulls后,如果第一条是判断的那个字段是空的,则默认取下一条,结果如下所示:

--lag() over()函数用法(取出前n行数据) lag(expresstion,<offset>,<default>) with a as (select 1 id,‘a‘ name from dual  union  select 2 id,‘b‘ name from dual  union  select 3 id,‘c‘ name from dual  union  select 4 id,‘d‘ name from dual  union  select 5 id,‘e‘ name from dual ) select id,name,lag(id,1,‘‘)over(order by name) from a;
--lead() over()函数用法(取出后N行数据)

lead(expresstion,<offset>,<default>) with a as (select 1 id,‘a‘ name from dual  union  select 2 id,‘b‘ name from dual  union  select 3 id,‘c‘ name from dual  union  select 4 id,‘d‘ name from dual  union  select 5 id,‘e‘ name from dual ) select id,name,lead(id,1,‘‘)over(order by name) from a;
--ratio_to_report(a)函数用法 Ratio_to_report() 括号中就是分子,over() 括号中就是分母
with a as (select 1 a from dual            union all select 1 a from dual            union  all select 1 a from dual            union all select 2 a from dual            union all select 3 a from dual            union all select 4 a from dual            union all select 4 a from dual            union all select 5 a from dual            ) select a, ratio_to_report(a)over(partition by a) b from a order by a;
with a as (select 1 a from dual            union all select 1 a from dual            union  all select 1 a from dual            union all select 2 a from dual            union all select 3 a from dual            union all select 4 a from dual            union all select 4 a from dual            union all select 5 a from dual            ) select a, ratio_to_report(a)over() b from a --分母缺省就是整个占比 order by a;
with a as (select 1 a from dual            union all select 1 a from dual            union  all select 1 a from dual            union all select 2 a from dual            union all select 3 a from dual            union all select 4 a from dual            union all select 4 a from dual            union all select 5 a from dual            ) select a, ratio_to_report(a)over() b from a group by a order by a;--分组后的占比

percent_rank用法

计算方法:所在组排名序号-1除以该组所有的行数-1,如下所示自己计算的pr1与通过percent_rank函数得到的值是一样的: SELECT a.deptno,        a.ename,        a.sal,        a.r,        b.n,        (a.r-1)/(n-1) pr1,        percent_rank() over(PARTITION BY a.deptno ORDER BY a.sal) pr2   FROM (SELECT deptno,                ename,                sal,                rank() over(PARTITION BY deptno ORDER BY sal) r --计算出在组中的排名序号           FROM emp          ORDER BY deptno, sal) a,        (SELECT deptno, COUNT(1) n FROM emp GROUP BY deptno) b --按部门计算每个部门的所有成员数  WHERE a.deptno = b.deptno;

cume_dist函数

计算方法:所在组排名序号除以该组所有的行数,但是如果存在并列情况,则需加上并列的个数-1,           如下所示自己计算的pr1与通过percent_rank函数得到的值是一样的: SELECT a.deptno,        a.ename,        a.sal,        a.r,        b.n,        c.rn,        (a.r + c.rn - 1) / n pr1,        cume_dist() over(PARTITION BY a.deptno ORDER BY a.sal) pr2   FROM (SELECT deptno,                ename,                sal,                rank() over(PARTITION BY deptno ORDER BY sal) r           FROM emp          ORDER BY deptno, sal) a,        (SELECT deptno, COUNT(1) n FROM emp GROUP BY deptno) b,        (SELECT deptno, r, COUNT(1) rn,sal           FROM (SELECT deptno,sal,                        rank() over(PARTITION BY deptno ORDER BY sal) r                   FROM emp)          GROUP BY deptno, r,sal          ORDER BY deptno) c --c表就是为了得到每个部门员工工资的一样的个数  WHERE a.deptno = b.deptno    AND a.deptno = c.deptno(+)    AND a.sal = c.sal;

percentile_cont函数

含义:输入一个百分比(该百分比就是按照percent_rank函数计算的值),返回该百分比位置的平均值 如下,输入百分比为0.7,因为0.7介于0.6和0.8之间,因此返回的结果就是0.6对应的sal的1500加上0.8对应的sal的1600平均 SELECT ename,        sal,        deptno,        percentile_cont(0.7) within GROUP(ORDER BY sal) over(PARTITION BY deptno) "Percentile_Cont",        percent_rank() over(PARTITION BY deptno ORDER BY sal) "Percent_Rank"   FROM emp  WHERE deptno IN (30, 60);

若输入的百分比为0.6,则直接0.6对应的sal值,即1500 SELECT ename,        sal,        deptno,        percentile_cont(0.6) within GROUP(ORDER BY sal) over(PARTITION BY deptno) "Percentile_Cont",        percent_rank() over(PARTITION BY deptno ORDER BY sal) "Percent_Rank"   FROM emp  WHERE deptno IN (30, 60);

PERCENTILE_DISC函数

功能描述:返回一个与输入的分布百分比值相对应的数据值,分布百分比的计算方法见函数CUME_DIST,如果没有正好对应的数据值,就取大于该分布值的下一个值。 注意:本函数与PERCENTILE_CONT的区别在找不到对应的分布值时返回的替代值的计算方法不同
SAMPLE:下例中0.7的分布值在部门30中没有对应的Cume_Dist值,所以就取下一个分布值0.83333333所对应的SALARY来替代
SELECT ename,        sal,        deptno,        percentile_disc(0.7) within GROUP(ORDER BY sal) over(PARTITION BY deptno) "Percentile_Disc",        cume_dist() over(PARTITION BY deptno ORDER BY sal) "Cume_Dist"   FROM emp  WHERE deptno IN (30, 60);

时间: 2024-10-05 07:03:14

over partition by与group by的相关文章

sqlserver中分区函数 partition by与 group by 区别 删除关键字段重复列

partition  by关键字是分析性函数的一部分,它和聚合函数(如group by)不同的地方在于它能返回一个分组中的多条记录,而聚合函数一般只有一条反映统计值的记录, partition  by用于给结果集分组,如果没有指定那么它把整个结果集作为一个分组. partition by 与group by不同之处在于前者返回的是分组里的每一条数据,并且可以对分组数据进行排序操作.后者只能返回聚合之后的组的数据统计值的记录. 用法 : select *,ROW_NUMBER() over( pa

over partition by与group by 的区别

今天看到一个老兄的问题, 大概如下: 查询出部门的最低工资的userid 号 表结构: D号      工资      部门 userid salary   dept 1      2000      1 2      1000      1 3      500       2 4      1000      2 有一个高人给出了一种答案: SELECT MIN (salary) OVER (PARTITION BY dept ) salary, dept    FROM ss 运行后得到:

kafka partition(分区)与 group

1.原理图 2.原理描述 一个topic 可以配置几个partition,produce发送的消息分发到不同的partition中,consumer接受数据的时候是按照group来接受,kafka确保每个partition只能同一个group中的同一个consumer消费,如果想要重复消费,那么需要其他的组来消费.Zookeerper中保存这每个topic下的每个partition在每个group中消费的offset 新版kafka把这个offsert保存到了一个__consumer_offse

Oracle高级查询之over(partition by...)

为了方便学习和测试,所有的例子都是在Oracle自带用户Scott下建立的. [sql] view plain copy print? create table EMP ( empno    NUMBER(4) not null, ename    VARCHAR2(10), job      VARCHAR2(9), mgr      NUMBER(4), hiredate DATE, sal      NUMBER(7,2), comm     NUMBER(7,2), deptno   N

oracle group by rollup,decode,grouping,nvl,nvl2,nullif,grouping_id,group_id,grouping sets,RATIO_TO

干oracle 047文章12当问题,经验group by 声明.因此邂逅group by  rollup,decode,grouping,nvl,nvl2,nullif,RATIO_TO_REPORT等一下. 1. decode  与if...then,case...when...这类流数据语句功能差点儿相同 decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义例如以下: IF 条件=值1 THEN RETURN(值1) ELSIF 条件=值2 TH

oracle group by rollup decode grouping nvl等判断或者小计合计心得

在做oracle 047第12题时,遇到group by 语句,由此遇到group by  rollup,decode,grouping,nvl,nvl2,nullif,RATIO_TO_REPORT等. 1. decode  与if...then,case...when...这类流数据语句功能差不多 decode(条件,值1,返回值1,值2,返回值2,...值n,返回值n,缺省值) 该函数的含义如下: IF 条件=值1 THEN RETURN(值1) ELSIF 条件=值2 THEN RETU

ORACLE 物理读 逻辑读 一致性读 当前模式读总结浅析

在ORACLE数据库中有物理读(Physical Reads).逻辑读(Logical Reads).一致性读(Consistant Get).当前模式读(DB Block Gets)等诸多概念,如果不理解或混淆这些概念的话,对你深入理解一些知识无疑是一个障碍,但是这些概念确实挺让让人犯晕的.下面我们总结.学习一下这方面的知识点.捋一捋他们的关系和特点,希望对你有所帮助. 物理读(Physical Reads) 从磁盘读取数据块到内存的操作叫物理读,当SGA里的高速缓存(Cache Buffer

Hadoop分区与分组

下面以<Hadoop权威指南>中的一个例子来解释分区与分组的关系. 对于一般的键,只需要key值相同,则对应的value就会分配至同一个 reduce中: 对于复合键,形式为TextPair<key1,key2>(关于复合键,可参考另一篇关于TextPair的博文http://blog.csdn.net/until_v/article/details/40867973),通过控制 key1来进行分区,则具有相同的 key1的值会被划分至同一个分区中,但此时如果 key2不相同,则不

H.264视频的RTP荷载格式

Status of This Memo This document specifies an Internet standards track protocol for the   Internet community, and requests discussion and suggestions for   improvements.  Please refer to the current edition of the "Internet   Official Protocol Stand