【開發篇sql】 分析函式(二) 行篩選相關的函式

yellowlee發表於2010-05-20

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中的firstlastminmax的意義:

正對上面的查詢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.

firstlast很容易理解。Dense_rank的特點上面的keep中的dense_rank first或者dense_rank last都可能會取到多行。

hiredate修改為to_char(hiredate,'yyyy')以後,有了在同一年份入職的員工,那麼first其實會把第一組年份的員工行都取了,外層使用min(a.sal)或者max(a.sal)就是再對組中的員工求最大最小工錢值。

接下來再看看first_valuelast_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排序了,每增加一條資料,都會取當前的firstlast,因此可以看到每行的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.

再來看laglead,分別用兩個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.

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/16179598/viewspace-663169/,如需轉載,請註明出處,否則將追究法律責任。

相關文章