Oracle之开窗函数 - 详解 AND Rows



解析:
三个位置:最前边一行,最后边一行,当前行
位置永远是自上而下的


drop table emp purge;


CREATE TABLE emp
(
  emp_id    NUMBER(6),
  ename  VARCHAR2(45),
  dept_id   NUMBER(4),
  hire_date DATE,
  sal    NUMBER(8,2)
);


--创建emp数据
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (101, 'Tom',     20,  TO_DATE('21-09-1989', 'DD-MM-YYYY'), 2000);
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (102, 'Mike',    20,  TO_DATE('13-01-1993', 'DD-MM-YYYY'), 8000);
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (120, 'John',    50,  TO_DATE('18-07-1996', 'DD-MM-YYYY'), 1000);
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (121, 'Joy',     50,  TO_DATE('10-04-1997', 'DD-MM-YYYY'), 4000);
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (122, 'Rich',    50,  TO_DATE('01-05-1995', 'DD-MM-YYYY'), 3000);
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (123, 'Kate',    50,  TO_DATE('10-10-1997', 'DD-MM-YYYY'), 5000);
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (124, 'Jess',    50,  TO_DATE('16-11-1999', 'DD-MM-YYYY'), 6000);
INSERT INTO emp (emp_id, ename, dept_id, hire_date, sal) VALUES (100, 'Stev',    10,  TO_DATE('01-01-1990', 'DD-MM-YYYY'), 7000);
COMMIT;


set linesize 2000
set pagesize 2000
col emp_id format 999
col dept_id format 99
col sal format 9999
col ename format a5
col hire_date FORMAT DATE




SELECT 
 emp_id,ename,dept_id,hire_date,sal, 
-- 首先按dept_id进行分组,其次按照hire_date进行排序,然后再把入职时间小于等于自身的所有员工薪资进行累计。
-- partition by 与 order by 先根据deptno分组,然后在组内依次累加
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date) sum_sal_part_order,
-- 按dept_id进行分组,并统计该部门下所有员工的薪资。
-- 只有分组,没有order by即没有依次关系,直接对组内数据进行求和操作
 SUM(sal) OVER (PARTITION BY dept_id) sum_sal_part,
-- 直接按照hire_date进行分组,并再把入职时间小于等于自身的所有员工薪资进行累计。
-- 只有order by,没有分组直接order by数据依次累加
 SUM(sal) OVER (ORDER BY hire_date) sum_sal_order
FROM emp order by dept_id,hire_date;


EMP_ID ENAME DEPT_ID HIRE_DATE        SAL SUM_SAL_PART_ORDER SUM_SAL_PART SUM_SAL_ORDER
------ ----- ------- -------------- ----- ------------------ ------------ -------------
   100 Stev       10 01-1月 -90      7000               7000         7000          9000
   101 Tom        20 21-9月 -89      2000               2000        10000          2000
   102 Mike       20 13-1月 -93      8000              10000        10000         17000
   122 Rich       50 01-5月 -95      3000               3000        19000         20000
   120 John       50 18-7月 -96      1000               4000        19000         21000
   121 Joy        50 10-4月 -97      4000               8000        19000         25000
   123 Kate       50 10-10月-97      5000              13000        19000         30000
   124 Jess       50 16-11月-99      6000              19000        19000         36000


   SELECT 
 emp_id,ename,dept_id,hire_date,sal, 
-- 以下均为首先按dept_id进行分组,其次按照hire_date进行排序,且所有统计不能跨越其所在分区,故不再重复
-- 窗口范围为该分区的第一行到该分区的最后一行,与sum_sal_part等同
-- 分区内,第一行到分区最后一行 累加
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date   ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) sum1,
-- 窗口范围为该分区的第一行到本行,与sum_sal_part_order等同
-- 分区内,第一行到本行 累加
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date   ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum2,
-- 窗口范围为该分区的第一行到本行前一行,统计的是第一行到本行前一行薪资的累计
-- 数字+null=null,分区内,第一行到前一行 累加?????(没看懂)
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date   ROWS BETWEEN UNBOUNDED PRECEDING AND 1/*value_expr*/ PRECEDING) sum3,
 -- 窗口范围为该分区的第一行到本行后一行,统计的是第一行到本行后一行薪资的累计
--  分区内,第一行到后一行 累加
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date   ROWS BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING) sum4
FROM emp order by dept_id,hire_date;  
  
   
EMP_ID ENAME DEPT_ID HIRE_DATE        SAL SUM_1_TO_LAST SUM_1_TO_CUR SUM_1_TO_CURBEF1 SUM_1_TO_CURAFT1
------ ----- ------- -------------- ----- ------------- ------------ ---------------- ----------------
   100 Stev       10 01-1月 -90      7000          7000         7000                              7000
   101 Tom        20 21-9月 -89      2000         10000         2000                             10000   
   102 Mike       20 13-1月 -93      8000         10000        10000             2000            10000   
   122 Rich       50 01-5月 -95      3000         19000         3000                              4000   
   120 John       50 18-7月 -96      1000         19000         4000             3000             8000   
   121 Joy        50 10-4月 -97      4000         19000         8000             4000            13000   
   123 Kate       50 10-10月-97      5000         19000        13000             8000            19000   
   124 Jess       50 16-11月-99      6000         19000        19000            13000            19000   
                                                                                          
            解说SUM1_TO_CUR(dept_id=50部分)                                                                   
                                                                                          
 ---从第1行hiredates顺序到当前行(也就是到第1行),多少?该3000就3000                       
 ---比第1行hiredates顺序到当前行(也就是到第2行),多少?3000+1000=4000                    
 ---比第1行hiredates顺序到当前行(也就是到第3行),多少?3000+1000+4000                      
 ---比第1行hiredates顺序到当前行(也就是到第4行),多少?3000+1000+4000+5000                 
 ---比第1行hiredates顺序到当前行(也就是到第4行),多少?3000+1000+4000+5000+6000          
  
                  
                    解说SUM1_TO_CURaft1 (dept_id=50部分)                                   
                                                                                    
    ---从第1行hiredates顺序到当前行后1行(也就是到第2行),多少?300+1000                    
    ---比第1行hiredates顺序到当前行后1行(也就是到第3行),多少?3000+1000+4000           
    ---比第1行hiredates顺序到当前行后1行(也就是到第4行),多少?3000+1000+4000+5000         
    ---比第1行hiredates顺序到当前行后1行(也就是到第5行),多少?3000+1000+4000+5000+6000    
    ---比第1行hiredates顺序到当前行后1行(也就是到第6行,第6行没记录了,那结果和上一次一样)
  
SELECT 
 emp_id,ename,dept_id,hire_date,sal, 
-- 窗口范围为本行和该分区的最后一行,统计的是大于等于本记录hire_date之后的所有薪资
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING) sum_cur_to_last,
-- 窗口范围只是本行,所以与本行薪资一样
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN CURRENT ROW AND CURRENT ROW) sum_cur,
-- 窗口范围为本行到本行的后一行,统计的本行到后一行的薪资累计
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN CURRENT ROW AND 1/*value_expr*/ FOLLOWING) sum_cur_to_aft1,
-- 窗口范围为本行和本行的后一行,统计的本行前一行到本分区最后一行的薪资累计,如本行为分区首行,则直接从本行开始算起
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN 1/*value_expr*/ PRECEDING AND UNBOUNDED FOLLOWING) sum_curbef1_to_last
FROM emp  order by dept_id,hire_date;  


EMP_ID ENAME DEPT_ID HIRE_DATE        SAL SUM_CUR_TO_LAST    SUM_CUR SUM_CUR_TO_AFT1 SUM_CURBEF1_TO_LAST
------ ----- ------- -------------- ----- --------------- ---------- --------------- -------------------
   100 Stev       10 01-1月 -90      7000            7000       7000            7000                7000   
   101 Tom        20 21-9月 -89      2000           10000       2000           10000               10000       
   102 Mike       20 13-1月 -93      8000            8000       8000            8000               10000   
   122 Rich       50 01-5月 -95      3000           19000       3000            4000               19000    
   120 John       50 18-7月 -96      1000           16000       1000            5000               19000   
   121 Joy        50 10-4月 -97      4000           15000       4000            9000               16000   
   123 Kate       50 10-10月-97      5000           11000       5000           11000               15000   
   124 Jess       50 16-11月-99      6000            6000       6000            6000               11000       


   
               解说SUM_CUR_TO_AFT1(dept_id=50部分)                                  
                                                                                     
    ---从第1行hiredates顺序到当前行(也就是第1行)到下1行,多少?3000+1000             
    ---比第1行hiredates顺序到当前行(也就是第2行)到下1行,多少?1000+4000            
    ---比第1行hiredates顺序到当前行(也就是第3行)到下1行,多少?4000+5000          
    ---比第1行hiredates顺序到当前行(也就是第4行)到下1行,多少?5000+6000        
    ---比第1行hiredates顺序到当前行(也就是第5行)到下1行,多少?下行没了,那就是6000 
 
SELECT 
 emp_id,ename,dept_id,hire_date,sal, 
-- 窗口范围为该分区的本行和本行前一行,统计的是当本行和本行的薪资累计
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN 1/*value_expr*/ PRECEDING AND CURRENT ROW) sum_cur_to_bef1,
-- 窗口范围为该分区的本行前value_expr1到本行前value_expr2的累计,本例为本行前2行和前1行的累计,强调value_expr1>=value_expr2
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN 2/*value_expr1*/ PRECEDING AND 1/*value_expr2*/ PRECEDING) sum_curbef2_to_bef1,
-- 窗口范围为该分区的本行前value_expr1到本行后value_expr2的累计,本例为本行前1行到后2行的累计
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN 1/*value_expr1*/ PRECEDING AND 2/*value_expr2*/ FOLLOWING) sum_curbef1_to_aft2,
-- 窗口范围为该分区的本行后一行和本区最后一行,统计的是本行后一行和本区最后一行的薪资累计
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN 1/*value_expr*/ FOLLOWING AND UNBOUNDED FOLLOWING) sum_curaft1_to_last
FROM emp order by dept_id,hire_date;  


EMP_ID ENAME DEPT_ID HIRE_DATE        SAL SUM_CUR_TO_BEF1 SUM_CURBEF2_TO_BEF1 SUM_CURBEF1_TO_AFT2 SUM_CURAFT1_TO_LAST
------ ----- ------- -------------- ----- --------------- ------------------- ------------------- -------------------
   100 Stev       10 01-1月 -90      7000            7000                                    7000
   101 Tom        20 21-9月 -89      2000            2000                                   10000        8000           
   102 Mike       20 13-1月 -93      8000           10000                2000               10000                       
   122 Rich       50 01-5月 -95      3000            3000                                    8000       16000           
   120 John       50 18-7月 -96      1000            4000                3000               13000       15000           
   121 Joy        50 10-4月 -97      4000            5000                4000               16000       11000           
   123 Kate       50 10-10月-97      5000            9000                5000               15000        6000           
   124 Jess       50 16-11月-99      6000           11000                9000               11000                       


   
             解说SUM_CURBEF2_TO_BEF1(dept_id=50部分)                                     
                                                                                       
  ---从第1行hiredate顺序到当前行(也就是第1行),往前2位,没数字,往前1位,依然没数字!                 
  ---比第1行hiredate顺序到当前行(也就是第2行)往前2位,没数字,往前1位,3000                      
  ---比第1行hiredate顺序到当前行(也就是第3行)往前2位,3000,往前1位,1000,是3000+1000                 
  ---比第1行hiredate顺序到当前行(也就是第4行)往前2位,1000,往前1位,4000,是1000+4000                  
  ---比第1行hiredate顺序到当前行(也就是第5行)往前2位,4000,往前1位,5000,是4000+5000       
   


SELECT 
 emp_id,ename,dept_id,hire_date,sal, 
-- 窗口范围为该分区的本行后value_expr1到本行后value_expr2的累计,本例为本行后1行和后2行的累计,强调value_expr1<=value_expr2
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS BETWEEN 1/*value_expr1*/ FOLLOWING AND 2/*value_expr2*/ FOLLOWING) sum_curaft1_to_after2,
-- 窗口范围为该分区的第一行,结束行缺省为本行,与之前出现的sum_sal_part_order,sum_1_to_cur等同
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS UNBOUNDED PRECEDING) sum_1_to_cur,
-- 窗口范围仅为当前行,所以与本行薪资一样,与之前出现的sum_cur一样
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS CURRENT ROW) sum_cur,
-- 窗口范围为该分区的本行和本行前一行,统计的是本行前一行和本行的薪资累计,与之前出现的sum_cur一样
 SUM(sal) OVER (PARTITION BY dept_id ORDER BY hire_date  ROWS 1/*value_expr*/ PRECEDING) sum_cur_to_bef1
FROM emp order by dept_id,hire_date;  


EMP_ID ENAME DEPT_ID HIRE_DATE        SAL SUM_CURAFT1_TO_AFTER2 SUM_1_TO_CUR    SUM_CUR SUM_CUR_TO_BEF1
------ ----- ------- -------------- ----- --------------------- ------------ ---------- ---------------
   100 Stev       10 01-1月 -90      7000                               7000       7000            7000
   101 Tom        20 21-9月 -89      2000                  8000         2000       2000            2000     
   102 Mike       20 13-1月 -93      8000                              10000       8000           10000     
   122 Rich       50 01-5月 -95      3000                  5000         3000       3000            3000     
   120 John       50 18-7月 -96      1000                  9000         4000       1000            4000     
   121 Joy        50 10-4月 -97      4000                 11000         8000       4000            5000     
   123 Kate       50 10-10月-97      5000                  6000        13000       5000            9000     
   124 Jess       50 16-11月-99      6000                              19000       6000           11000     
                                                                                                            
    解说SUM_CURAFTER1_TO_AFTER1(dept_id=50部分)                                                                                                                                              
                                                                                        
---从第1行hiredate顺序到当前行(也就是第1行),往后1位,1000,后2位,4000,是1000+4000   --如果涉及到当前行的运算,比如 CURRENT ROW的关键字,则必须要有order by    
---从第1行hiredate顺序到当前行(也就是第2行),往后1位,4000,后2位,5000,是4000+5000         
---从第1行hiredate顺序到当前行(也就是第3行),往后1位,5000,后2位,6000,是5000+6000   请注意:如下语句无法执行,会报ORA-30485: 在窗口说明中丢失 ORDER BY 表达式的错误
---从第1行hiredate顺序到当前行(也就是第4行),往后1位,6000,后2位,没了SELECT emp_id,ename,dept_id,hire_date,sal,     
---从第1行hiredate顺序到当前行(也就是第5行),往后1位,没了,后2位,更没了!       SUM(sal) OVER(PARTITION BY dept_id order by hire_date ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum1,
       SUM(sal) OVER(PARTITION BY dept_id  ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) sum2
  FROM emp
 order by dept_id, hire_date;








rows 是关键字,指定窗口由物理行构成,即物理座位排数。


between…and是关键字,用来指定窗口的起始点和终结点;
Unbounded preceding指明窗口开始于分组的第一行;
Current row,作为起始点,指明窗口开始于当前行或当前值;作为终结点,指明窗口结束于当前行或当前值;
Unbounded following指明窗口结束于分组的最后一行;
Value_expr为物理或逻辑偏移量表达式。




Windowing_clause用来指定分组中当前行的计算范围。
不论rows还是range窗口,窗口总是在分组中从上至下滑动的。
窗口范围可以由between…and限定,也可以不用between…and,不用的都表示窗口到当前行结束。


ROWS窗口,是由分组排序后分组中若干连续的行构成的窗口。
以下是全部合法的ROWS窗口范围:
1)rows between unbounded preceding and unbounded following
窗口开始于分组第一行,结束于分组最后一行。
2)rows [between] unbounded preceding [and current row]
窗口开始于分组第一行,结束于当前行。
3)rows between unbounded preceding and value_expr preceding
窗口开始于分组第一行,结束于当前行前value_expr行。
4)rows between unbounded preceding and value_expr following
窗口开始于分组第一行,结束于当前行后value_expr行。
5)rows between current row and unbounded following
窗口开始于当前行,结束于分组最后一行。
6)rows [between current row and] current row
窗口开始于当前行,结束于当前行。
7)rows between current row and value_expr following
窗口开始于当前行,结束于当前行后value_expr行。
8)rows between value_expr preceding and unbounded following
窗口开始于当前行前value_expr行,结束于分组最后一行。
9)rows [between value_expr] preceding [and current row]
窗口开始于当前行前value_expr行,结束于当前行。
10)rows between value_expr1 preceding and value_expr2 preceding
窗口开始于当前行前value_expr1行,结束于当前行前value_expr2行。这里一定要满足value_expr1>=value_expr2。
11)rows between value_expr1 preceding and value_expr2 following
窗口开始于当前行前value_expr1行,结束于当前行后value_expr2行。
12)rows between value_expr following and unbounded following
窗口开始于当前行后value_expr行,结束于分组最后一行。
13)rows between value_expr1 following and value_expr2 following
窗口开始于当前行后value_expr1行,结束于当前行后value_expr2行。这里一定要满足value_expr1<=value_expr2
14)rows unbounded preceding
与2等价。
15)rows current row
与6等价。
16)rows value_expr preceding
与9等价。
   

你可能感兴趣的:(Oracle之分析函数)