设为首页 收藏本站
查看: 634|回复: 0

[经验分享] ORACLE窗口函数over的使用

[复制链接]

尚未签到

发表于 2016-8-4 09:38:35 | 显示全部楼层 |阅读模式

与聚集函数一样,窗口函数也针对定义的行集(组)执行聚集,但它不像聚集函数那样每组之返回一个值,窗口函数可以为每组返回多个值。实际上,DB2中称这种函数为联机分析处理OLAP函数,而Oracle把它们称为解析函数,但ISO SQL标准把它们称为窗口函数。窗口函数一般在OLAP分析、制作报表过程中会使用到。


窗口函数:


聚合函数 over()


聚合函数 over(partition by 字段)—分区


聚合函数 over(order by 字段)--框架字句







本文以Oracle11g中HR模式下的Employees表为例子来试着了解窗口函数,


Employees表结构如下:


SQL> desc employees
名称                                      是否为空? 类型
----------------------------------------- -------- ----------------------------
EMPLOYEE_ID                              
NOT NULL NUMBER(6)
FIRST_NAME                                         
VARCHAR2(20)
LAST_NAME                                 
NOT NULL VARCHAR2(25)
EMAIL                                    
NOT NULL VARCHAR2(25)
PHONE_NUMBER                                       
VARCHAR2(20)
HIRE_DATE                                 
NOT NULL DATE
JOB_ID                                    NOT NULL VARCHAR2(10)
SALARY                                             NUMBER(8,2)
COMMISSION_PCT                                     NUMBER(2,2)
MANAGER_ID                                         NUMBER(6)
DEPARTMENT_ID                                      NUMBER(4)






计算部门号位20的员工总数:


SQL> edit
1  
select first_name,department_id,count(*) over()
2  
from employees
3*
where department_id=20
SQL> /
FIRST_NAME           DEPARTMENT_ID
COUNT(*)OVER()                              
-------------------- ------------- --------------                              
Michael                         20              2                              
Pat                             20              2         






窗口 ,函数 count(*) over() 对于查询返回的每一行,它返回了表中所有行的计数。


在深入研究Over字句之前,一定要注意:在SQL处理中,窗口函数都是最后一步执行,而且仅位于Order by字句之前。








  • 分区
  

使用Partiton by字句定义行的分区或组,可以用paritition by对定义的行组计算聚集(当遇到新组的时候复位),并返回每个值(每个组中的每个成员),而不是一个用一个组表示表中的这个值的所有实例。如:


SQL> edit
1  
select first_name,department_id,count(*) over(partition by department_id) as cnt
2  
from employees
3*
order by 2
SQL> /
FIRST_NAME           DEPARTMENT_ID        CNT                                   
-------------------- ------------- ----------                                   
Jennifer                        10          1                                   
Michael                         20          2                                   
Pat                             20          2                                   
Den                             30          6                                   
Alexander                       30          6                                   
Shelli                          30          6                                   
Sigal                           30          6                                   
Guy                             30          6                                   
Karen                           30          6                                   
Susan                           40          1                                   
Matthew                         50         45   

。。。。。。。。。。
如上结果所示:对于同一个部门(同一个分区)的每个员工的cnt值相同,这是由于在遇到新部门之前不会重置聚集。      





另外partition by字句的优点是:在同一个select语句中,一个窗口函数的计算独立于按其他列分区的其他窗口函数的计算。例如下面的查询,返回每个员工、他的部门、他的部门中的员工数、他的职位以及跟他相同职位的员工数:






1  select first_name,department_id,count(*) over (partition by department_id) as dept_cnt,
2  job_id,
3  
count(*) over(partition by job_id) as job_cnt
4  
from employees
5*
order by 2
SQL> /
FIRST_NAME           DEPARTMENT_ID   DEPT_CNT JOB_ID        JOB_CNT            
-------------------- ------------- ---------- ---------- ----------            
Jennifer                        10          1 AD_ASST             1            
Michael                         20          2 MK_MAN              1            
Pat                             20          2 MK_REP              1            
Sigal                           30          6 PU_CLERK            5            
Alexander                       30          6 PU_CLERK            5            
Shelli                          30          6 PU_CLERK            5            
Karen                           30          6 PU_CLERK            5            
Den                             30          6 PU_MAN              1            
Guy                             30          6 PU_CLERK            5            
Susan                           40          1 HR_REP              1            
Donald                          50         45 SH_CLERK           20   




  • 框架字句:


当在窗口函数over字句中使用order by 字句时,就指定了两件事:


1、分区中的行如何排序


2、在计算中包含哪些行


请看下面的查询,它计算了30号员工的工资的累计和


1  select department_id,first_name,hire_date,salary,
2  
sum(salary) over(partition by department_id) as total1,
3  
sum(salary) over() as total2,
4  
sum(salary) over(order by hire_date) as running_total
5  
from employees
6*
where department_id=30
SQL> /
DEPARTMENT_ID FIRST_NAME           HIRE_DATE          SALARY     TOTAL1         
------------- -------------------- -------------- ---------- ----------         
TOTAL2 RUNNING_TOTAL                                                        
---------- -------------                                                        
30 Den                  07-12月-02          11000      24900         
24900         11000                                                        
30 Alexander            18-5月 -03           3100      24900         
24900         14100                                                        
30 Sigal                24-7月 -05           2800      24900         
24900         16900                                                        

DEPARTMENT_ID FIRST_NAME           HIRE_DATE          SALARY     TOTAL1         
------------- -------------------- -------------- ---------- ----------         
TOTAL2 RUNNING_TOTAL                                                        
---------- -------------                                                        
30 Shelli               24-12月-05           2900      24900         
24900         19800                                                        
30 Guy                  15-11月-06           2600      24900         
24900         22400                                                        
30 Karen                10-8月 -07           2500      24900         
24900         24900                                                        

已选择6行。




上面的查询语句相当于:





  1  select department_id,first_name,hire_date,salary,
2  
sum(salary) over(partition by department_id) as total1,
3  
sum(salary) over() as total2,
4  
sum(salary) over(order by hire_date range between unbounded preceding and current row) as running_total
5  
from employees
6*
where department_id=30







也就说默认情况下会告诉查询:计算所有行的和,即从当前行开始、包括它前面的所有行。对从当前行开始、包括它前面的所有行进行求和,就可以得到累计和效果了。




通过,框架字句允许定义数据的不同“子窗口”,以便在计算中使用,有很多方式可以指定这样的子窗口。如:


1  select department_id,first_name,salary,
2  
sum(salary) over (order by hire_date range between unbounded preceding and current row) as run_total1,
3  
sum(salary) over(order by hire_date rows between 1 preceding and current row) as run_total2,
4  
sum(salary) over(order by hire_date range between current row and unbounded following) as run_total3,
5  
sum(salary) over(order by hire_date rows between current row and 1 following) as run_total4
6  
from employees
7*
where department_id=30
SQL> /
DEPARTMENT_ID FIRST_NAME               SALARY RUN_TOTAL1 RUN_TOTAL2 RUN_TOTAL3  
------------- -------------------- ---------- ---------- ---------- ----------  
RUN_TOTAL4                                                                     
----------                                                                     
30 Den                       11000      11000      11000      24900  
14100                                                                     
30 Alexander                  3100      14100      14100      13900  
5900                                                                     
30 Sigal                      2800      16900       5900      10800  
5700                                                                     

DEPARTMENT_ID FIRST_NAME               SALARY RUN_TOTAL1 RUN_TOTAL2 RUN_TOTAL3  
------------- -------------------- ---------- ---------- ---------- ----------  
RUN_TOTAL4                                                                     
----------                                                                     
30 Shelli                     2900      19800       5700       8000  
5500                                                                     
30 Guy                        2600      22400       5500       5100  
5100                                                                     
30 Karen                      2500      24900       5100       2500  
2500                                                                     

已选择6行。






其中:


rangebetweenunbounded
preceding
andcurrentrow
指定计算当前行开始、当前行之前的所有值;


rowsbetween1
preceding
andcurrentrow
指定计算当前行的前一行开始,其范围一直延续到当前行;


rangebetweencurrentrowandunbounded
following 指定计算从当前行开始,包括它后面的所有行;


rowsbetweencurrentrowand1
following 指定计算当前行和它后面的一行;




最后一个例子,展示 了框架字句对查询输出的影响,请看下面查询:


1  select first_name,salary,min(salary) over(order by salary) min1,
2  
max(salary) over(order by salary) max1,
3  
min(salary) over(order by salary range between unbounded preceding and unbounded following) min2,
4  
max(salary) over(order by salary range between unbounded preceding and unbounded following) max2,
5  
min(salary) over(order by salary range between current row and current row) min3,
6  
max(salary) over(order by salary range between current row and current row) max3,
7  
max(salary) over(order by salary rows between 3 preceding and 3 following) max4
8*
from employees
SQL> /
FIRST_NAME               SALARY      
MIN1       MAX1       MIN2       MAX2     
-------------------- ---------- ---------- ---------- ---------- ----------     
MIN3       MAX3       MAX4                                                
---------- ---------- ----------                                                
TJ                         2100       2100       2100       2100      24000     
2100       2100       2400                                                
Steven                     2200       2100       2200       2100      24000     
2200       2200       2400                                                
Hazel                      2200       2100       2200       2100      24000     
2200       2200       2500      


请仔细观察计算结果,领会子窗口的内涵;

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-252610-1-1.html 上篇帖子: Oracle 常用函数的总结(一) 下篇帖子: 复杂查询语句的使用,Oracle
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表