【FUN】开窗函数

目录

 

定义

参数含义

over

partition by

order by

rank()/dense_rank()

rank()

dense_rank()

测试一

方法一

方法二

方法三

first_value()

last_value()

测试二

方法一

方法二

测试三

lead(col_name,x,y)

lag()


定义

用于计算给予组的某种聚合值,和聚合函数不同之处是:对于每个组返回多个行,而聚合函数对于每个组只返回一行,开窗函数制定了分析函数工作的数据窗口大小,它可以随着行的变化而变化

 

参数含义

over

表示在什么条件之上

partition by

表示按什么划分

order by

表示排列顺序(rank()/dense_rank()时,必须要带order by否则报非法)

rank()/dense_rank()

分级

rank()

跳跃排序,如果有两个第一名时,再后面就是第三名

SQL> select ename,deptno,sal,rank() over(partition by deptno order by sal) a from emp;
 
ENAME       DEPTNO   SAL          A

---------- ------- ----- ----------
MILLER          10  1300          1
CLARK           10  2450          2
KING            10  5000          3
SMITH           20   800          1
ADAMS           20  1100          2
JONES           20  2975          3
SCOTT           20  3000          4
FORD            20  3000          4
JAMES           30   950          1
MARTIN          30  1250          2
WARD            30  1250          2
TURNER          30  1500          4
ALLEN           30  1600          5
BLAKE           30  2850          6

 

14 rows selected.

dense_rank()

连续排序,如果有两个第一名,那么后面还是第二名

SQL> select ename,deptno,sal,dense_rank() over(partition by deptno order by sal) a from emp;
 
ENAME       DEPTNO   SAL          A

---------- ------- ----- ----------
MILLER          10  1300          1
CLARK           10  2450          2
KING            10  5000          3
SMITH           20   800          1
ADAMS           20  1100          2
JONES           20  2975          3
SCOTT           20  3000          4
FORD            20  3000          4
JAMES           30   950          1
MARTIN          30  1250          2
WARD            30  1250          2
TURNER          30  1500          3
ALLEN           30  1600          4
BLAKE           30  2850          5
 
14 rows selected.

 

测试一

想要得到emp表中每个部门工资最高的员工姓名、职位、工资以及部门编号

方法一

可以使max()

SQL>
select ename 姓名,job 职位,sal 工资,deptno 部门 from

(select ename, job, e.sal, e.deptno from emp e,

(select deptno, max(sal) sal from emp group by deptno) t

where e.deptno = t.deptno   and e.sal = t.sal) 

order by 部门;
 

姓名       职位             工资  部门
---------- ---------- ---------- -----
KING       PRESIDENT        5000    10
SCOTT      ANALYST          3000    20
FORD       ANALYST          3000    20
BLAKE      MANAGER          2850    30

 

方法二

使用开窗函数

SQL>

select ename 姓名,job 职位,sal 工资,deptno 部门 from (

select ename,

job,sal,

deptno,

dense_rank() over(partition by deptno order by sal desc) r

from emp

)

where r=1;
 

姓名       职位             工资  部门
---------- ---------- ---------- -----
KING       PRESIDENT        5000    10
SCOTT      ANALYST          3000    20
FORD       ANALYST          3000    20
BLAKE      MANAGER          2850    30

 

这句话的意思是按部门划分的基础上,把工资进行降序排列分级,级别从小到大排列其中最小值必定为一

单独执行from后面的查询可以看出具体是怎么分级

SQL> select ename,job,sal,deptno,dense_rank() over(partition by deptno order by sal desc) r from emp;
 
ENAME      JOB           SAL  DEPTNO          R

---------- ----------- ----- ------- ----------
KING       PRESIDENT    5000      10          1
CLARK      MANAGER      2450      10          2
MILLER     CLERK        1300      10          3
SCOTT      ANALYST      3000      20          1
FORD       ANALYST      3000      20          1
JONES      MANAGER      2975      20          2
ADAMS      CLERK        1100      20          3
SMITH      CLERK         800      20          4
BLAKE      MANAGER      2850      30          1
ALLEN      SALESMAN     1600      30          2
TURNER     SALESMAN     1500      30          3
MARTIN     SALESMAN     1250      30          4
WARD       SALESMAN     1250      30          4
JAMES      CLERK         950      30          5
 
14 rows selected.

 

方法三

利用first_value()/last_value()配合partition by

first_value()

记录结果最前面的值

last_value()

记录结果最后面的值

SQL>
select ename 姓名,job 职位,deptno 部门,max_sal 工资 from (

select ename,job,sal,deptno,first_value(sal) over(partition by deptno order by sal desc) max_sal

from emp)

where max_sal=sal;
 

姓名       职位          部门  工资
---------- ------------ ----- -----
KING       PRESIDENT       10  5000
SCOTT      ANALYST         20  3000
FORD       ANALYST         20  3000
BLAKE      MANAGER         30  2850

单独使用firet_value()

SQL> select ename,job,sal,deptno,first_value(sal) over(partition by deptno order by sal desc) max_sal from emp;
 
ENAME      JOB                 SAL     DEPTNO    MAX_SAL

---------- ------------ ---------- ---------- ----------
KING       PRESIDENT          5000         10       5000
CLARK      MANAGER            2450         10       5000
MILLER     CLERK              1300         10       5000
SCOTT      ANALYST            3000         20       3000
FORD       ANALYST            3000         20       3000
JONES      MANAGER            2975         20       3000
ADAMS      CLERK              1100         20       3000
SMITH      CLERK               800         20       3000
BLAKE      MANAGER            2850         30       2850
ALLEN      SALESMAN           1600         30       2850
TURNER     SALESMAN           1500         30       2850
MARTIN     SALESMAN           1250         30       2850
WARD       SALESMAN           1250         30       2850
JAMES      CLERK               950         30       2850
 
14 rows selected.

单独使用last_value()

测试二

想要得到emp表中每个员工的姓名,部门编号,工资,与低工资的差额,与最高工资差额

方法一

依旧使用max()/min()

SQL>
select e.ename 姓名,e.job 职位,e.sal 工资,e.sal-f.min 最低差额,f.max-e.sal 最高差额,e.deptno 部门 from

emp e,

(select deptno,min(sal) min,max(sal) max from emp group by deptno) f
where e.deptno=f.deptno
order by e.deptno,e.sal;
 

姓名       职位             工资   最低差额   最高差额  部门
---------- ---------- ---------- ---------- ---------- -----
MILLER     CLERK            1300          0       3700    10
CLARK      MANAGER          2450       1150       2550    10
KING       PRESIDENT        5000       3700          0    10
SMITH      CLERK             800          0       2200    20
ADAMS      CLERK            1100        300       1900    20
JONES      MANAGER          2975       2175         25    20
SCOTT      ANALYST          3000       2200          0    20
FORD       ANALYST          3000       2200          0    20
JAMES      CLERK             950          0       1900    30
WARD       SALESMAN         1250        300       1600    30
MARTIN     SALESMAN         1250        300       1600    30
TURNER     SALESMAN         1500        550       1350    30
ALLEN      SALESMAN         1600        650       1250    30
BLAKE      MANAGER          2850       1900          0    30
 
14 rows selected.

方法二

使用开窗函数

SQL>

select
      ename 姓名,
      job
职位,
      nvl(sal-
min(sal) over(partition by deptno),0) 最低差额,
      nvl(
max(sal) over(partition by deptno)-sal,0) 最高差额,
      deptno
部门
from emp
order by deptno,sal;
 

姓名       职位         最低差额   最高差额  部门
---------- ---------- ---------- ---------- -----
MILLER     CLERK               0       3700    10
CLARK      MANAGER          1150       2550    10
KING       PRESIDENT        3700          0    10
SMITH      CLERK               0       2200    20
ADAMS      CLERK             300       1900    20
JONES      MANAGER          2175         25    20
SCOTT      ANALYST          2200          0    20
FORD       ANALYST          2200          0    20
JAMES      CLERK               0       1900    30
MARTIN     SALESMAN          300       1600    30
WARD       SALESMAN          300       1600    30
TURNER     SALESMAN          550       1350    30
ALLEN      SALESMAN          650       1250    30
BLAKE      MANAGER          1900          0    30
 
14 rows selected.

 

测试三

查询emp表中员工姓名、职位、比自己工资低一名的差额,比自己工资高一名的差额、部门号

这种需求单纯用group by无法实现

不过可以使用开窗函数配合分析函数lead()/lag()解决

lead(col_name,x,y)

表示当前记录后面的第x行记录中col_name列的值,没有则默认值为y,如果不带x,y参数侧查找当前记录后面第一行col_name列中的值,没有则默认为null

 

【FUN】开窗函数

lag()

【FUN】开窗函数

表示当前记录前面的第x行记录中col_name列的值,没有则默认值为y,如果不带x,y参数侧查找当前记录前面第一行col_name列中的值,没有则默认为null

SQL>
select
    ename 姓名,
    job
职位,sal 工资,
    deptno
部门,
    nvl(
lead(sal) over(partition by deptno order by sal)- sal,0) 前一位高查额,
    nvl(sal -
lag(sal) over(partition by deptno order by sal),0) 后一位低差额
from emp;
 

姓名       职位          工资  部门 前一位高查额 后一位低差额
---------- ------------ ----- ----- ------------ ------------
MILLER     CLERK         1300    10         1150            0
CLARK      MANAGER       2450    10         2550         1150
KING       PRESIDENT     5000    10            0         2550
SMITH      CLERK          800    20          300            0
ADAMS      CLERK         1100    20         1875          300
JONES      MANAGER       2975    20           25         1875
SCOTT      ANALYST       3000    20            0           25
FORD       ANALYST       3000    20            0            0
JAMES      CLERK          950    30          300            0
MARTIN     SALESMAN      1250    30            0          300
WARD       SALESMAN      1250    30          250            0
TURNER     SALESMAN      1500    30          100          250
ALLEN      SALESMAN      1600    30         1250          100
BLAKE      MANAGER       2850    30            0         1250
 
14 rows selected.

 

 

上一篇:mysql之mysql学习准备的数据库04


下一篇:8-5多线程----线程的通信(2)生产者消费者例题