|
2,行筛选相关的函数keep,first,last,first_value,last_value,lag,lead
先来看两个查询,一个实现的是部门内最早雇佣的员工中的工资最多与最小的值,一个是实现工资最高和最低的员工中入职时间最早或最晚的值:
查询1:
SQL> select a.deptno,a.hiredate,a.sal,
2 min(a.sal) keep(dense_rank first order by hiredate desc) over(partition by a.deptno) first,
3 max(a.sal) keep(dense_rank last order by hiredate desc) over(partition by a.deptno) last
4 from scott.emp a;
DEPTNO HIREDATE SAL FIRST LAST
---------- --------- ---------- ---------- ----------
10 09-JUN-81 2450 1300 2450
10 17-NOV-81 5000 1300 2450
10 23-JAN-82 1300 1300 2450
20 02-APR-81 2000 1100 800
20 03-DEC-81 3000 1100 800
20 23-MAY-87 1100 1100 800
20 17-DEC-80 800 1100 800
20 19-APR-87 3000 1100 800
30 22-FEB-81 1250 950 1600
30 08-SEP-81 1500 950 1600
30 20-FEB-81 1600 950 1600
DEPTNO HIREDATE SAL FIRST LAST
---------- --------- ---------- ---------- ----------
30 03-DEC-81 950 950 1600
30 01-MAY-81 2850 950 1600
30 28-SEP-81 1250 950 1600
14 rows selected.
查询2:
SQL> select a.deptno,a.sal,a.hiredate,
2 min(a.hiredate) keep(dense_rank first order by a.sal desc) over(partition by a.deptno) first,
3 max(a.hiredate) keep(dense_rank last order by a.sal desc) over(partition by a.deptno) last
4 from scott.emp a;
DEPTNO SAL HIREDATE FIRST LAST
---------- ---------- --------- --------- ---------
10 2450 09-JUN-81 17-NOV-81 23-JAN-82
10 5000 17-NOV-81 17-NOV-81 23-JAN-82
10 1300 23-JAN-82 17-NOV-81 23-JAN-82
20 2000 02-APR-81 03-DEC-81 17-DEC-80
20 3000 03-DEC-81 03-DEC-81 17-DEC-80
20 1100 23-MAY-87 03-DEC-81 17-DEC-80
20 800 17-DEC-80 03-DEC-81 17-DEC-80
20 3000 19-APR-87 03-DEC-81 17-DEC-80
30 1250 22-FEB-81 01-MAY-81 03-DEC-81
30 1500 08-SEP-81 01-MAY-81 03-DEC-81
30 1600 20-FEB-81 01-MAY-81 03-DEC-81
DEPTNO SAL HIREDATE FIRST LAST
---------- ---------- --------- --------- ---------
30 950 03-DEC-81 01-MAY-81 03-DEC-81
30 2850 01-MAY-81 01-MAY-81 03-DEC-81
30 1250 28-SEP-81 01-MAY-81 03-DEC-81
14 rows selected.
上面的例子中时间没有完全相同的,那么简单修改一下,则可以更好的理解keep中的first和last与min和max的意义:
正对上面的查询1来修改得到
查询3:
SQL> select a.deptno,to_char(hiredate,'yyyy') hiredate,a.sal,
2 min(a.sal) keep(dense_rank first order by to_char(hiredate,'yyyy') desc) over(partition by a.deptno) first,
3 max(a.sal) keep(dense_rank last order by to_char(hiredate,'yyyy') desc) over(partition by a.deptno) last
4 from scott.emp a;
DEPTNO HIRE SAL FIRST LAST
---------- ---- ---------- ---------- ----------
10 1981 2450 1300 5000
10 1981 5000 1300 5000
10 1982 1300 1300 5000
20 1981 2000 1100 800
20 1981 3000 1100 800
20 1987 1100 1100 800
20 1980 800 1100 800
20 1987 3000 1100 800
30 1981 1250 950 2850
30 1981 1500 950 2850
30 1981 1600 950 2850
DEPTNO HIRE SAL FIRST LAST
---------- ---- ---------- ---------- ----------
30 1981 950 950 2850
30 1981 2850 950 2850
30 1981 1250 950 2850
14 rows selected.
first和last很容易理解。Dense_rank的特点上面的keep中的dense_rank first或者dense_rank last都可能会取到多行。
在hiredate修改为to_char(hiredate,'yyyy')以后,有了在同一年份入职的员工,那么first其实会把第一组年份的员工行都取了,外层使用min(a.sal)或者max(a.sal)就是再对组中的员工求最大最小工钱值。
接下来再看看first_value和last_value,有四个查询例子:
这个查询按deptno开窗找第一个和最后一个sal:
SQL> select a.empno,a.deptno,to_char(hiredate,'yyyy') hiredate,a.sal,
2 first_value(a.sal) over(partition by a.deptno ) first,
3 last_value(a.sal) over(partition by a.deptno ) last
4 from scott.emp a;
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7782 10 1981 2450 2450 1300
7839 10 1981 5000 2450 1300
7934 10 1982 1300 2450 1300
7566 20 1981 2000 2000 3000
7902 20 1981 3000 2000 3000
7876 20 1987 1100 2000 3000
7369 20 1980 800 2000 3000
7788 20 1987 3000 2000 3000
7521 30 1981 1250 1250 1250
7844 30 1981 1500 1250 1250
7499 30 1981 1600 1250 1250
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7900 30 1981 950 1250 1250
7698 30 1981 2850 1250 1250
7654 30 1981 1250 1250 1250
14 rows selected.
下面的查询在上面的基础上增加了order by deptno语句:
SQL> select a.empno,a.deptno,to_char(hiredate,'yyyy') hiredate,a.sal,
2 first_value(a.sal) over(partition by a.deptno order by deptno) first,
3 last_value(a.sal) over(partition by a.deptno order by deptno) last
4 from scott.emp a;
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7934 10 1982 1300 1300 5000
7782 10 1981 2450 1300 5000
7839 10 1981 5000 1300 5000
7369 20 1980 800 800 3000
7876 20 1987 1100 800 3000
7566 20 1981 2000 800 3000
7788 20 1987 3000 800 3000
7902 20 1981 3000 800 3000
7900 30 1981 950 950 2850
7654 30 1981 1250 950 2850
7521 30 1981 1250 950 2850
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7844 30 1981 1500 950 2850
7499 30 1981 1600 950 2850
7698 30 1981 2850 950 2850
14 rows selected.
下面的查询是按照sal升序排序后的,这样每个部门下面按照sal排序了,每增加一条数据,都会取当前的first和last,因此可以看到每行的last都在变化。
SQL> select a.empno,a.deptno,to_char(hiredate,'yyyy') hiredate,a.sal,
2 first_value(a.sal) over(partition by a.deptno order by sal) first,
3 last_value(a.sal) over(partition by a.deptno order by sal) last
4 from scott.emp a;
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7934 10 1982 1300 1300 1300
7782 10 1981 2450 1300 2450
7839 10 1981 5000 1300 5000
7369 20 1980 800 800 800
7876 20 1987 1100 800 1100
7566 20 1981 2000 800 2000
7788 20 1987 3000 800 3000
7902 20 1981 3000 800 3000
7900 30 1981 950 950 950
7654 30 1981 1250 950 1250
7521 30 1981 1250 950 1250
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7844 30 1981 1500 950 1500
7499 30 1981 1600 950 1600
7698 30 1981 2850 950 2850
14 rows selected.
再修改一下,order by rowid,效果差不多:
SQL> select a.empno,a.deptno,to_char(hiredate,'yyyy') hiredate,a.sal,
2 first_value(a.sal) over(partition by a.deptno order by rowid) first,
3 last_value(a.sal) over(partition by a.deptno order by rowid) last
4 from scott.emp a;
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7782 10 1981 2450 2450 2450
7839 10 1981 5000 2450 5000
7934 10 1982 1300 2450 1300
7369 20 1980 800 800 800
7566 20 1981 2000 800 2000
7788 20 1987 3000 800 3000
7876 20 1987 1100 800 1100
7902 20 1981 3000 800 3000
7499 30 1981 1600 1600 1600
7521 30 1981 1250 1600 1250
7654 30 1981 1250 1600 1250
EMPNO DEPTNO HIRE SAL FIRST LAST
---------- ---------- ---- ---------- ---------- ----------
7698 30 1981 2850 1600 2850
7844 30 1981 1500 1600 1500
7900 30 1981 950 1600 950
14 rows selected.
再来看lag和lead,分别用两个sql来求部门内按照hiredate排序后的每个苦工上一个或者下一个的工钱值:
SQL> select a.empno,
2 a.deptno,
3 a.hiredate,
4 a.sal,
5 lag(sal, 1, 0) over(partition by a.deptno order by hiredate asc) pre_sal
6 from scott.emp a;
EMPNO DEPTNO HIREDATE SAL PRE_SAL
---------- ---------- --------- ---------- ----------
7782 10 09-JUN-81 2450 0
7839 10 17-NOV-81 5000 2450
7934 10 23-JAN-82 1300 5000
7369 20 17-DEC-80 800 0
7566 20 02-APR-81 2000 800
7902 20 03-DEC-81 3000 2000
7788 20 19-APR-87 3000 3000
7876 20 23-MAY-87 1100 3000
7499 30 20-FEB-81 1600 0
7521 30 22-FEB-81 1250 1600
7698 30 01-MAY-81 2850 1250
EMPNO DEPTNO HIREDATE SAL PRE_SAL
---------- ---------- --------- ---------- ----------
7844 30 08-SEP-81 1500 2850
7654 30 28-SEP-81 1250 1500
7900 30 03-DEC-81 950 1250
14 rows selected.
SQL> select a.empno,
2 a.deptno,
3 a.hiredate,
4 a.sal,
5 lead(sal, 1, 0) over(partition by a.deptno order by hiredate asc) next_sal
6 from scott.emp a;
EMPNO DEPTNO HIREDATE SAL NEXT_SAL
---------- ---------- --------- ---------- ----------
7782 10 09-JUN-81 2450 5000
7839 10 17-NOV-81 5000 1300
7934 10 23-JAN-82 1300 0
7369 20 17-DEC-80 800 2000
7566 20 02-APR-81 2000 3000
7902 20 03-DEC-81 3000 3000
7788 20 19-APR-87 3000 1100
7876 20 23-MAY-87 1100 0
7499 30 20-FEB-81 1600 1250
7521 30 22-FEB-81 1250 2850
7698 30 01-MAY-81 2850 1500
EMPNO DEPTNO HIREDATE SAL NEXT_SAL
---------- ---------- --------- ---------- ----------
7844 30 08-SEP-81 1500 1250
7654 30 28-SEP-81 1250 950
7900 30 03-DEC-81 950 0
14 rows selected. |
|