oracle 分析函數以及實例解析

1.排名函數:

RANK and DENSE_RANK Functions

語法如下:

RANK ( ) OVER ( [query_partition_clause] order_by_clause )

DENSE_RANK ( ) OVER ( [query_partition_clause]order_by_clause )

在排名函數中order by是不可選字段,表示你要按什麼進行排名,partition是可選字段,如果沒有partition則表示對全部數據進行排名,如果有partition則表示在分區內進行排序。

 

我們先來看一個例子:

SQL> SELECT EMPNO,

  2         DEPTNO,

  3         SUM(SAL) SAL,

  4         RANK() OVER(ORDER BY SUM(SAL) DESC)RANK_DESC,

  5         RANK() OVER(ORDER BY SUM(SAL))RANK_ASC,

  6         DENSE_RANK() OVER(ORDER BY SUM(SAL)DESC) DENSE

  7    FROM EMP

  8   GROUP BY DEPTNO, EMPNO;

 

     EMPNO     DEPTNO        SAL RANK_DESC   RANK_ASC      DENSE

---------- ---------- ---------- ---------- --------------------

      7900         30        950         14          1         12

      7876        20       1100         13          2         11

      7521         30       1250         11          3         10

      7654         30       1250         11          3         10

      7934         10       1300         10          5          9

      7844         30       1500          9          6          8

      7499         30       1600          8          7          7

      7782         10       2450          7          8          6

      7698         30       2850          6          9          5

      7566         20       2975          5         10          4

      7902         20       3000          3         11          3

 

     EMPNO     DEPTNO        SAL RANK_DESC   RANK_ASC      DENSE

---------- ---------- ---------- ---------- --------------------

      7788         20       3000          3         11          3

      7839         10       5000          2         13          2

      7369         20     10000          1         14          1

 

已選擇14行。

在以上這個例子中我們可以看到,oracle默認是按照asc進行排名的,rank函數的排名是有間隙的,比如說上面兩個11名,接下來就是13名,而dense_rank是沒有間隙的。

接下來看一下partition是如何處理的

SQL> SELECT EMPNO,

  2         DEPTNO,

  3         SUM(SAL) SAL,

  4         RANK() OVER(PARTITION BY deptno ORDERBY SUM(SAL) DESC) rank_par

  5    FROM EMP

  6   GROUP BY DEPTNO, EMPNO;

     EMPNO     DEPTNO        SAL  RANK_PAR

---------- ---------- ---------- ----------

      7839         10       5000          1

      7782         10       2450          2

      7934         10      1300          3

      7369         20     10000          1

      7788         20       3000          2

      7902         20       3000          2

      7566         20       2975          4

      7876         20       1100          5

      7698         30      2850          1

      7499         30       1600          2

      7844         30       1500          3

 

     EMPNO     DEPTNO        SAL  RANK_PAR

---------- ---------- ---------- ----------

      7521         30       1250          4

      7654         30       1250          4

      7900         30        950          6

 

已選擇14行。

可以看到oracledeptno內進行了排序,也就是以deptno爲分區進行排序。

NTILEFunction

語法如下:

NTILE (expr) OVER([query_partition_clause] order_by_clause)

ntile函數會按照order by對數據進行切片,但是有一個比較有趣的情況,那就是當數據不能平分時,Oracle會將不能平分的數據按照片號從高到低一個一個的分配,例子如下:

SQL> SELECT EMPNO,

  2         DEPTNO,

  3         SUM(SAL) SAL,

  4         ntile(4) OVER(ORDER BY SUM(SAL) DESC)til

  5    FROM EMP

  6   GROUP BY DEPTNO,EMPNO;

 

    EMPNO     DEPTNO        SAL       TILE

---------- ---------- ---------- ----------

      7369         20     10000          1

      7839         10       5000          1

      7788         20       3000          1

      7902         20       3000          1

      7566         20      2975          2

      7698         30       2850          2

      7782         10       2450          2

      7499         30       1600          2

      7844         30       1500          3

      7934         10       1300          3

      7654        30       1250          3

 

     EMPNO     DEPTNO        SAL       TILE

---------- ---------- ---------- ----------

      7521         30       1250          4

      7876         20       1100          4

      7900         30        950          4

 

ROW_NUMBERFunction

ROW_NUMBER ( ) OVER ([query_partition_clause] order_by_clause )

這個函數會根據order by對每一行分配一個特定的編號,從1開始。例子如下:

SQL> SELECT EMPNO,

  2         DEPTNO,

  3         SUM(SAL) SAL,

  4         row_number() OVER(ORDER BY SUM(SAL)DESC) row_number

  5    FROM EMP

  6   GROUP BY DEPTNO,EMPNO;

 

     EMPNO     DEPTNO        SAL ROW_NUMBER

---------- ---------- ---------- ----------

      7369         20     10000          1

      7839         10      5000          2

      7788         20       3000          3

      7902         20       3000          4

      7566         20       2975          5

      7698         30       2850          6

      7782         10       2450          7

      7499         30      1600          8

      7844         30       1500          9

      7934         10       1300         10

      7654         30       1250         11

 

     EMPNO     DEPTNO        SAL ROW_NUMBER

---------- ---------- ---------- ----------

      7521         30       1250         12

      7876         20       1100         13

      7900         30        950         14

 

其它一些函數並不常用,請參照官方文檔。

2.window函數

先來看看Oracle官方文檔的介紹吧

Windowing functions can be used to computecumulative, moving, and centered aggregates. They return a value for each rowin the table, which depends on other rows in the corresponding window. Withwindowing aggregate functions, you can calculate moving andcumulative versions of SUM, AVERAGE, COUNT, MAX,MIN, andmany more functions. They can be used only inthe SELECT and ORDER BY clauses of the query.Windowing aggregate functions include the convenientFIRST_VALUE, which returnsthe first value in the window; and LAST_VALUE, which returns the lastvalue in the window. These functions provide access to more than one row of atable without a self-join.

 語法如下:

analytic_function([arguments ])
  
OVER (analytic_clause)

where analytic_clause=
    
[ query_partition_clause ]
     [ order_by_clause [ windowing_clause] ]

andquery_partition_clause =
   
PARTITION BY
      { value_expr[, value_expr ]...
      }

and windowing_clause =
    
{ ROWS | RANGE }
     { BETWEEN
       { UNBOUNDED PRECEDING
     | CURRENT ROW
     | value_expr { PRECEDING | FOLLOWING}
     }
     AND
     { UNBOUNDED FOLLOWING
     | CURRENT ROW
     | value_expr { PRECEDING | FOLLOWING}
     }
   | { UNBOUNDED PRECEDING
     | CURRENT ROW
     | value_expr PRECEDING
     }
   }

 

在瞭解之前先了解一下rowsrange的區別,

rows表示一個物理窗口,也就是排序後,按排序結果的行號對應確定窗口

Range是默認窗口,表示一個行和行之間的邏輯關係(當前行的排序鍵的value加或減邏輯偏移量得到當前行對應的邏輯窗口的範圍)

Cumulative Aggregate Function

下面這個例子表示對一個部門的工資進行累加

SQL> SELECT EMPNO,

  2        DEPTNO,

  3        SUM(sal),

  4        SUM(SAL) OVER(

  5         PARTITION BY deptno ORDER BY empno DESCROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW

  6        ) row_number

  7   FROM EMP

  8  GROUP BY DEPTNO,EMPNO,sal;

 

     EMPNO    DEPTNO   SUM(SAL) ROW_NUMBER

---------- -------------------- ----------

      7934         10       1300       1300

      7839         10       5000       6300

      7782         10       2450       8750

      7902         20       3000       3000

      7876         20       1100       4100

      7788         20       3000      7100

      7566         20       2975     10075

      7369         20     10000      20075

      7900         30        950        950

      7844         30       1500       2450

      7698         30       2850       5300

 

     EMPNO    DEPTNO   SUM(SAL) ROW_NUMBER

---------- -------------------- ----------

      7654         30       1250       6550

      7521         30       1250       7800

      7499         30       1600       9400

這個例子中,窗口開始於partition by的第一條數據,結束於當前行,oracle默認的結束爲currentrow

MovingAggregate Function

SQL> SELECT EMPNO,

  2        DEPTNO,

  3        SUM(sal),

  4        SUM(SAL) OVER(

  5        PARTITION BY deptno ORDER BY empno DESC ROWS BETWEEN 1 PRECEDING AND 1Following

  6        ) rows_sum

  7    FROMEMP

  8  GROUP BY DEPTNO,EMPNO,sal;

 

     EMPNO    DEPTNO   SUM(SAL)   ROWS_SUM

---------- -------------------- ----------

      7934         10       1300       6300     --這個表示1 PRECEDING,就是向前推進一行

      7839         10       5000       8750     --假如這個是當前行

      7782         10       2450       7450     --這個表示1 Following,就是向後推進一行

      7902         20       3000       4100

      7876         20       1100       7100

      7788         20       3000       7075

      7566         20       2975     15975

      7369         20     10000      12975

      7900         30        950       2450

      7844         30       1500       5300

      7698         30       2850       5600

 

     EMPNO    DEPTNO   SUM(SAL)   ROWS_SUM

---------- ---------- --------------------

      7654         30       1250       5350

      7521         30       1250       4100

      7499         30       1600       2850

 

下面我們來看range是怎麼樣進行偏移的。

CenteredAggregate Function   

SQL> SELECT EMPNO,

  2        DEPTNO,

  3         SUM(SAL),

  4        SUM(SAL) OVER(PARTITION BY DEPTNO ORDER BY SAL DESC RANGE BETWEEN 10

0 PRECEDING AND 300FOLLOWING) ROWS_SUM

  5   FROM EMP

  6  GROUP BY DEPTNO, EMPNO, SAL;

 

     EMPNO    DEPTNO   SUM(SAL)   ROWS_SUM

---------- ---------- --------------------

      7839         10       5000       5000

      7782         10       2450       2450

      7934         10       1300       1300

      7369         20     10000      10000

      7788         20       3000       8975

      7902        20       3000       8975

      7566         20       2975       8975

      7876         20       1100       1100

      7698         30       2850       2850

      7499         30       1600       3100  ----開始處

      7844         30       1500       5600   --假如這個是當前行,那麼上面就表示的範圍是1500-300=1200 1600之間

 

     EMPNO    DEPTNO   SUM(SAL)   ROWS_SUM

---------- -------------------- ----------

      7521         30       1250       3450

      7654         30       1250       3450--結束處

      7900         30       950        950

 

升序range窗口preceding含義是比當前行小xx值,following含義是比當前行大xx值,降序range窗口preceding含義是比當前行大xx值,following含義是比當前行小xx值。

3.Reporting函數

語法如下:

{SUM |AVG | MAX | MIN | COUNT | STDDEV | VARIANCE ... }
  ([ALL | DISTINCT] {value expression1[,...] | *})
   OVER ([PARTITION BY valueexpression2[,...]])

這個比較簡單不在用實例說明了。

 

RATIO_TO_REPORTFunction

 

語法如下:RATIO_TO_REPORT( expr ) OVER ( [query_partition_clause] )

 

這個函數表示expr這個值在expr所在字段和中所佔的比例,實例如下:

 

SQL> SELECT DEPTNO,

  2         EMPNO,

  3         SUM(SAL) SAL,

  4         SUM(SAL) OVER() TOTAL,

  5         to_char(RATIO_TO_REPORT(SUM(sal))OVER(),'9990.99') RATIO

  6    FROM EMP

  7   GROUP BY DEPTNO, EMPNO,sal;

 

    DEPTNO      EMPNO        SAL     TOTAL RATIO

---------- ---------- ---------- ---------- --------

        30       7499       1600     38225     0.04       --1600/38225

        20       7566       2975     38225     0.08

        20       7788       3000     38225     0.08

        10       7839       5000     38225     0.13

        20       7876      1100      38225     0.03

        20       7369     10000      38225     0.26

        30       7654       1250     38225     0.03

        30       7521       1250     38225     0.03

        20       7902       3000     38225     0.08

        10      7782       2450      38225    0.06

        10       7934       1300     38225     0.03

 

    DEPTNO      EMPNO        SAL     TOTAL RATIO

---------- ---------- ---------- ---------- --------

        30       7698       2850     38225     0.07

        30       7844       1500     38225     0.04

        30       7900        950     38225     0.02

 

4.LAG/LEAD

 

語法如下:

 

{LAG | LEAD} (value_expr [, offset] [, default] ) [RESPECT NULLS|IGNORE NULLS]
  
OVER ( [query_partition_clause] order_by_clause)

 

Offset 表示偏移量,當指定ignore nulls在發生偏移時oracle會忽略null

 

例子如下:

 

SQL> SELECT DEPTNO,

  2         empno,

  3         sal,

  4         LAG(sal,1) OVER(ORDER BY EMPNO DESC)LA,

  5         LEAD(SAL,1) OVER(ORDER BY EMPNO DESC)LE

  6    FROM EMP

  7   GROUP BY DEPTNO,empno,sal;

 

    DEPTNO      EMPNO        SAL         LA         LE

---------- ---------- ---------- ---------- ----------

        10       7934       1300                      3000

        20       7902       3000       1300        950

        30       7900        950       3000       1100

        20       7876       1100        950       1500

        30       7844       1500       1100       5000

        10       7839       5000       1500       3000

        20       7788      3000       5000       2450

        10       7782       2450       3000       2850

        30       7698       2850       2450       1250

        30       7654       1250       2850       2975

        20       7566       2975       1250       1250

 

    DEPTNO     EMPNO        SAL         LA         LE

---------- ---------- ---------- ---------- ----------

        30       7521       1250       2975       1600

        30       7499       1600       1250     10000

        20       7369     10000       1600

 

5.FIRST_VALUEand LAST_VALUE Functions

 

語法如下:

FIRST_VALUE|LAST_VALUE( <expr> ) [RESPECT NULLS|IGNORE NULLS] OVER (analytic clause );

 

這個函數用來返回窗口的第一個值或者最後一個值,但是這個有一個有趣的例子,我們來看看

先來看一個例子:

SQL> SELECT DEPTNO,

  2         EMPNO,

  3         sal,

  4         FIRST_VALUE(SAL) OVER(PARTITION BYDEPTNO ORDER BY EMPNO ROWS betwee

n unbounded preceding and current row) FIRST,

  5         LAST_VALUE(SAL) OVER(PARTITION BYDEPTNO ORDER BY empno rows between

 unbounded precedingand unbounded following)  LAST,

  6         LAST_VALUE(SAL) OVER(PARTITION BYDEPTNO ORDER BY empno rows between

 unbounded precedingand current row)  LAST2,

  7         LAST_VALUE(SAL) OVER(PARTITION BYDEPTNO ORDER BY empno) last3

  8    FROM EMP

  9  ;

 

    DEPTNO      EMPNO        SAL     FIRST       LAST      LAST2     LAST3

---------- ---------- ---------- ---------- -------------------- ----------

        10       7782       2450       2450       1300       2450       2450

        10       7839       5000       2450       1300       5000       5000

        10       7934       1300       2450       1300       1300       1300

        20       7369     10000      10000       3000     10000      10000

        20       7566       2975     10000       3000       2975       2975

        20      7788       3000      10000       3000       3000       3000

        20       7876       1100     10000       3000       1100       1100

        20       7902       3000     10000       3000       3000       3000

        30       7499      1600       1600        950       1600       1600

        30       7521       1250       1600        950       1250       1250

        30       7654       1250       1600        950       1250       1250

 

    DEPTNO      EMPNO        SAL     FIRST       LAST     LAST2      LAST3

---------- ---------- ---------- ---------- -------------------- ----------

        30       7698       2850       1600        950       2850       2850

        30       7844       1500       1600        950       1500       1500

        30       7900        950       1600        950        950        950

 

last3字段不是應該返回窗口的最後一個值嗎,但是結果總是讓人失望的,下面是我在pub上找到的一位大神的解釋。

 

--大神的解釋

對於分析函數,大家要注意:

1. 分析函數是在整個SQL查詢結束後(SQL語句中的ORDERBY的執行比較特殊)再進行的操作,也就是說

SQL語句中的ORDER BY也會影響分析函數的執行結果,請看:

SQL> select deptno,

  2        empno,

  3        ename,

  4        sal,

  5        hiredate,

  6        last_value(sal) over(partition by deptno) last_value

  7    from emp

  8   where deptno =30;

 

DEPTNO EMPNO ENAME           SAL HIREDATE    last_value

------ ----- ---------- -------------------- -----------

    30  7499ALLEN        1600.00 1981-02-20         950

    30  7521WARD         1250.00 1981-02-22         950

    30  7654MARTIN       1250.00 1981-09-28         950

    30  7698BLAKE        2850.00 1981-05-01         950

    30  7844TURNER       1500.00 1981-09-08         950

    30  7900JAMES         950.00 1981-12-03         950

 

6 rows selected

 

SQL> select deptno,

  2        empno,

  3        ename,

  4        sal,

  5        hiredate,

  6        last_value(sal) over(partition by deptno) last_value

  7    from emp

  8   where deptno =30

  9   order bydeptno,mgr;

 

DEPTNO EMPNO ENAME           SAL HIREDATE    last_value

------ ----- ---------- -------------------- -----------

    30  7499ALLEN        1600.00 1981-02-20        2850

    30  7521WARD         1250.00 1981-02-22        2850

    30  7654MARTIN       1250.00 1981-09-28        2850

    30  7900JAMES         950.00 1981-12-03        2850

    30  7844 TURNER      1500.00 1981-09-08        2850

    30  7698BLAKE        2850.00 1981-05-01        2850

 

6 rows selected

 

SQL> select deptno,

  2        empno,

  3        ename,

  4        sal,

  5        hiredate,

  6        last_value(sal) over(partition by deptno) last_value

  7    from emp

  8   where deptno =30

  9   order bydeptno,mgr desc;

 

DEPTNO EMPNO ENAME           SAL HIREDATE    last_value

------ ----- ---------- -------------------- -----------

    30  7698 BLAKE       2850.00 1981-05-01        1250

    30  7499ALLEN        1600.00 1981-02-20        1250

    30  7521WARD         1250.00 1981-02-22        1250

    30  7900JAMES         950.00 1981-12-03        1250

    30  7844TURNER       1500.00 1981-09-08        1250

    30  7654MARTIN       1250.00 1981-09-28        1250

 

6 rows selected

 

從上面的結果我們分析得出

a) 如果SQL語句中的OrderBy滿足分析函數分析時要求的排序,那麼SQL語句中的排序將先執行,分析

函數分析時就不必再排序

b) 如果SQL語句中的OrderBy不滿足分析函數分析時要求的排序,那麼SQL語句中的排序將最後在分

析函數分析結束後執行排序

 

 

2. 分析函數中包含三個分析子句:分組(Partition By), 排序(OrderBy),窗口(Window)

窗口就是分析函數分析時要處理的數據範圍,就拿SUM來說,它是SUM窗口中的記錄而不是整個分組中

的記錄,因此我們在想得到某個欄位的累計值時,我們需要把窗口指定到該分組中的第一行數據到當

前行,如果你指定該窗口從該分組中的第一行到最後一行,那麼該組中的每一個SUM值都會一樣,即整

個組的總和.

窗口子句在這裏我只說rows方式的窗口,range方式的這裏不提,此外滑動窗口也不提.窗口子句中

我們經常用到指定第一行,當前行,最後一行這樣的三個屬性.第一行是unbounded preceding,

前行是 current row,最後一行是unbounded following.

 

出現窗口子句,必須指定Order By子句,:

last_value(sal) over 

(partition by deptno order by sal rowsbetween unbounded preceding and unbounded following)

以上示例指定窗口爲整個分組.

 

當省略窗口子句時:

a) 如果存在Order By則默認的窗口是unboundedpreceding and current row

b) 如果同時省略Order By則默認的窗口是unboundedpreceding and unbounded following

 

如果省略分組,則把全部記錄當成一個組:

a) 如果存在Order By則默認窗口是unboundedpreceding and current row

b) 如果這時省略Order By則窗口默認爲unboundedpreceding and unbounded following

 

來自 <http://www.itpub.net/thread-717608-2-1.html>

Advanced Aggregates for Analysis

LISTAGG Function

這個函數是11g新提出來的,語法如下:

 

LISTAGG (<expr>[, <delimiter>) WITHIN GROUP (ORDER BY <oby_expression_list>)

 

Expr表示你要做處理的字段。

delimiter表示分隔符。

oby_expression_list表示要按照什麼排序。

 

看一個例子就明白了listagg做了什麼,下面這個sql列出了一個營業部所有的人員的名稱,並使用逗號分隔。

 

SQL> SELECT DEPTNO,

  2         LISTAGG(ename,',') WITHINGROUP(ORDER  BY DEPTNO) enamelist

  3    FROM EMP

  4   GROUP BY DEPTNO;

 

    DEPTNO ENAMELIST

------------------------------------------------------------

        10CLARK,KING,MILLER

        20ADAMS,FORD,JONES,SCOTT,SMITH

        30ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD

 

FIRST/LAST Functions

 

語法如下:

aggregate_functionKEEP ( DENSE_RANK LAST ORDER BY
 
expr [ DESC | ASC ] [NULLS { FIRST |LAST }]
  [, expr [ DESC | ASC ] [NULLS { FIRST |LAST }]]...)
[OVER query_partitioning_clause]

 

下面來看這個例子:

找出emp表中每個部門工資的最大值和最小值

 

SQL> SELECT DEPTNO,

 2        ENAME,

 3        EMPNO,

 4        SAL,

 5        hiredate,

 6        MAX(SAL) KEEP(DENSE_RANK FIRST ORDER BY empno) OVER(PARTITION BY DEP

TNO)"min_sal",

 7        MIN(SAL) KEEP(DENSE_RANK LAST ORDER BY empno) OVER(PARTITION BY DEPT

NO)"MAX_sal"

 8   FROM EMP;

 

   DEPTNO ENAME           EMPNO        SAL HIREDATE          min_sal    MAX_sal

 

---------- -------------------- ---------- -------------- ---------- ----------

 

       10 CLARK            7782       2450 09-6 -81          2450       1300

 

       10 KING             7839       5000 17-11-81          2450       1300

 

       10 MILLER           7934       1300 23-1 -82          2450       1300

 

       20 JONES            7566       2975 02-4 -81         10000       3000

 

       20 FORD             7902       3000 03-12-81         10000       3000

 

       20 ADAMS            7876       1100 23-5 -87         10000       3000

 

       20 SMITH            7369      10000 17-12-80         10000       3000

 

       20 SCOTT            7788       3000 19-4 -87         10000       3000

 

       30 WARD             7521       1250 22-2 -81          1600        950

 

       30 TURNER           7844       1500 08-9 -81          1600        950

 

       30 ALLEN            7499       1600 20-2 -81          1600        950

 

 

   DEPTNO ENAME           EMPNO        SAL HIREDATE          min_sal    MAX_sal

 

---------- -------------------- ---------- -------------- ---------- ----------

 

       30 JAMES            7900        950 03-12-81          1600        950

 

       30 BLAKE            7698       2850 01-5 -81          1600        950

 

       30 MARTIN           7654       1250 28-9 -81          1600        950

 

一些比較好的例子


連續數問題

要求對ID相同,num連續的,查找最小num以及val求和。

表中數據如下所示:

SQL> select * fromtest_tab;

       ID        NUM        VAL

---------- --------------------

        1          1         50

        1          2        100

        1          3        150

        1          5        250

        2          1        100

        2          3        400

        3          1        100

        3          2        200

 

SQL> SELECT ID,MIN(NUM), SUM(VAL)

 2   FROM (SELECT ID,

 3                 NUM,

 4                 VAL,

 5                 NUM - ROW_NUMBER()OVER(PARTITION BY ID ORDER BY NUM) RN  --使用當前值來減去rownumber

 6           FROM TEST_TAB)

 7  GROUP BY ID, RN

 8  ORDER BY 1, 2

 9  ;

 

       ID  MIN(NUM)   SUM(VAL)

---------- --------------------

        1          1        300

        1          5        250

        2          1        100

        2          3        400

        3          1        300

 模擬SQL*PLUS BREAK 問題

  SQL*PLUS提供BREAK命令,就是當前列值與前面相同,則置NULL,這是報表常用的一種手段。 

SQL> break on deptno;

SQL> select deptno,empno,ename from emp wheredeptno<30 order by deptno;

 

   DEPTNO      EMPNO ENAME

---------- ---------- ----------

       10       7934 MILLER

                7782 CLARK

                7839 KING

       20       7902 FORD

                7876 ADAMS

                7566 JONES

                7369 SMITH

                7788 SCOTT

 

已選擇8行。

 

SQL> SELECT DECODE(LAG(DEPTNO, 1) OVER(PARTITIONBY DEPTNO ORDER BY EMPNO),

  2                DEPTNO,

  3                NULL,

  4                DEPTNO) deptno,

  5         EMPNO,

  6         ENAME

  7    FROM EMP

  8    WHERE deptno<30;

 

DEPTNO         EMPNO ENAME

---------- ---------- ----------

10              7782 CLARK

                7839 KING

                7934 MILLER

20              7369 SMITH

                7566 JONES

                7788 SCOTT

                7876 ADAMS

                7902 FORD

 

重複行問題

SQL> select *from duprows;

 

        ID NAME

--------------------

         1 name

         2 name

         1 name

         3 name

         1 name

 

--通過以下方式找到重複行

SQL> SELECT *

  2   FROM (SELECT ID,

  3                 NAME,

  4                 ROW_NUMBER() OVER(PARTITION BYB.ID ORDER BY B.ROWID) RN

  5           FROM DUPROWS B) C

  6  WHERE C.RN > 1;

 

        ID NAME               RN

-------------------- ----------

         1 name                2

         1 name                3

金額攤派問題

平均分派問題,如何將金額平均分攤,並且小數也分攤掉,避免誤差

 

SQL> select *from demo7_1;

 

        ID    AMOUNT

--------------------

         1        100

         2         50

 

SQL> select *from demo7_2;

 

        ID   PERSONS

--------------------

         1          3

         2          2

 

SELECT ID,

       PERSONS,

       (CASE

         WHEN RN <= (AMOUNT - AMOUNT2) * 100THEN

          0.01

         ELSE

          0

       END) + JE AS JE,

       AMOUNT

--然後排序,與總金額有差額的補0.01

  FROM (SELECT T.*,

               SUM(JE) OVER(PARTITION BY ID) ASAMOUNT2,

               ROW_NUMBER() OVER(PARTITION BYID ORDER BY JE DESC) RN

          FROM (

                --先展開記錄數,用trunc先平均,只舍不入

                SELECT TT.*

                  FROM (SELECT T2.ID,

                                T2.PERSONS,

                                TRUNC(T1.AMOUNT/ T2.PERSONS, 2) JE,

                                T1.AMOUNTAMOUNT

                           FROM DEMO7_1 T1,DEMO7_2 T2

                          WHERE T1.ID = T2.ID)TT,

                        --構造最大的人數序列

                        (SELECT LEVEL RN

                           FROM DUAL

                         CONNECT BY LEVEL <=

                                    (SELECTMAX(PERSONS) MAX_NUM FROM DEMO7_2)) TM

                 WHERE TT.PERSONS >= TM.RN)T)

 

        ID   PERSONS         JE     AMOUNT

-------------------- ---------- ----------

         1          3     33.34        100

         1          3     33.33        100

         1          3     33.33        100

         2          2         25         50

         2          2         25         50


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章