解析:
三个位置:最前边一行,最后边一行,当前行
位置永远是自上而下的
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等价。