您的位置:首页 > 数据库 > Oracle

Oracle之开窗函数 - 详解 AND Rows

2017-11-05 02:39 1331 查看
解析:

三个位置:最前边一行,最后边一行,当前行

位置永远是自上而下的

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    
4000
         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
c1bd
(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等价。

   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: