• 分析函数讲解 老猫


    这几天感冒了,浑身很惬意就是没力气。

    工作上遇到了几个高级分组跟取数的东东,用到了分析函数:

    暂时列举出来,过几天等身体好了再补上教程。

    OVER:

    select distinct 保单号,
           生效时间,
           二级机构,
           产品名称,
           count(*) over(partition by 保单号, 生效时间, 二级机构,产品名称) 件数
      from WJRS_XB_20110825_04
     where 保单号 = 'HP02020000121158';

    Rank, Dense_rank, row_number:

    select 保单号,
           生效日期,
           产品,
           客户账号所属银行,
           失败原因,
           缴费金额,
           保单状态,
           缴别,
           二级机构,
           min(缴至日期) keep(dense_rank first order by 缴至日期 asc)  缴至日期,
           min(续期首次报盘转账日期) keep(dense_rank first order by 续期首次报盘转账日期 asc)  续期首次报盘转账日期
      from ZZXX_XB_20110824_07
      where 缴别='月缴'
     group by 保单号,
              生效日期,
              产品,
              客户账号所属银行,
              失败原因,
              缴费金额,
              保单状态,
              缴别,
              二级机构;

    Top/Bottom NFirst/LastNTile:

    暂无

     

     

    后续做实验的教程

     

     oracle分析函数over的用法
     
     分析函数,最早是从ORACLE8.1.6开始出现的,它的设计目的是为了解决诸如“累计计算”,“找出分组内百分比”,“前-N条查询”,“移动平均数 计算”"等问题。其实大部分的问题都可以用PL/SQL解决,但是它的性能并不能达到你所期望的效果。分析函数是SQL言语的一种扩充,它并不是仅仅试代 码变得更简单而已,它的速度比纯粹的SQL或者PL/SQL更快。现在这些扩展已经被纳入了美国国家标准化组织SQL委员会的SQL规范说明书中。
       分析函数是在一个记录行分组的基础上计算它们的总值。与集合函数不同,他们返回各分组的多行记录。行的分组被称窗口,并通过分析语句定义。对于每记录行, 定义了一个“滑动”窗口。该窗口确定“当前行”计算的范围。窗口的大小可由各行的实际编号或由时间等逻辑间隔确定。
        除了ORDER BY(按…排序)语句外,分析函数是一条查询被执行的操作。所有合并、WHERE、GROUP BY、HAVING语句都是分析函数处理之前完成的。因此,分析函数只出现在选择目录或ORDER BY(按…排序)语句中。
        前期数据准备:
    create table EMP
    (
      ENAME  VARCHAR2(10),
      DEPTNO VARCHAR2(2),
      SAL    NUMBER(10)
    )
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('CLARK', '10', 2450);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('MILLER', '10', 1300);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('KING', '10', 5000);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('FORD', '20', 3000);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('ADAMS', '20', 1100);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('JONES', '20', 2975);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('SCOTT ', '20', 3000);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('SMITH', '20', 800);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('ALLEN', '30', 1600);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('BLAKE', '30', 2850);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('JAMES', '30', 950);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('TURNER', '30', 1500);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('MARTIN ', '30', 1250);
    insert into EMP (ENAME, DEPTNO, SAL)
    values ('WARD', '30', 1250);
    commit;
    The Syntax句法:


    OVER (
      <Query-Partition-Clause>
      <Order-By-Clause>
      <Windowing-Clause>
    )
    根据划分表达式设置的规则,PARTITION BY(按…划分)将一个结果逻辑分成N个分组划分表达式。在此“划分”和“分组”用作同义词。分析函数独立应用于各个分组,并在应用时重置(按…排序)语 句规定了每个分组(划分)的数据如何排序。这必然影响分析函数的结果。

    窗口生成语句用以定义滑动或固定数据窗口,分析函数在分组内进行分析。该语句能够对分组中任意定义的滑动或固定窗口进行计算。
    Example: Calculate a running Total例:累计计算:本例中对某部门的工资进行逐行计算,每行包括之前所有行中工资的合计。
    SELECT ename "Ename", deptno "Deptno", sal "Sal",
      SUM(sal)
        OVER (ORDER BY deptno, ename) "Running Total",
      SUM(SAL)
        OVER (PARTITION BY deptno
              ORDER BY ename) "Dept Total",
      ROW_NUMBER()
        OVER (PARTITION BY deptno
              ORDER BY ENAME) "Seq"
    FROM emp
    ORDER BY deptno, ename
    /
    Ename  Deptno    Sal Running Total Dept Total  Seq
    ------ ------ ------ ------------- ---------- ----
    CLARK      10   2450          2450       2450    1
    KING            5000          7450      7450     2
    MILLER          1300          8750       8750    3

    ADAMS      20   1100          9850       1100    1
    FORD            3000         12850       4100    2
    JONES           2975         15825       7075    3
    SCOTT           3000         18825      10075    4
    SMITH            800         19625      10875    5

    ALLEN      30   1600         21225       1600    1
    BLAKE           2850         24075       4450    2
    JAMES            950         25025       5400    3
    MARTIN          1250         26275       6650    4
    TURNER          1500         27775       8150    5
    WARD            1250         29025       9400    6
    .本例指出了如何计算整条查询的“累计”。即使用排序后的整个结果集合,通过SUM(sal) OVER (ORDER BY deptno, ename)函数得到。可以进一步计算各个部门的累计值,该值在开始下一个部门计算时将被重置。由SUM(sal)中的PARTITION BY deptno实现。该条查询中指定划分语句将数据进行分组。根据排序规则(增加了“Seq”列以显示该状态),ROW_NUMBER()函数将每组返回的 记录行进行顺序编号,执行计划显示,整条查询仅需3条一致get函数就可以很好的执行。这一点是标准SQL甚至PL/SQL不能都实现的。
    Top-N Queries前N条查询:如何通过部分字段得到前N条记录?在未使用这些分析函数之前,很难对此类问题做出回答。人们关于前N条查询的说法存在问题。在 设计报告时,应留意这一点。我需要知道部门工资为前3名销售代表的谁。这句话的问题在于含混不清。因为存在重复的值,如果有四个人领着同样的工资,该怎么 处理?
    Example 1例1:从多到少排列销售人员的工资,取前三行。如果该部门少于三人,则返回的记录少于三个。
    SELECT * FROM (

      SELECT deptno, ename, sal, ROW_NUMBER()
      OVER (
        PARTITION BY deptno ORDER BY sal DESC
      ) Top3 FROM emp
    )
    WHERE Top3 <= 3
    /
    DEPTNO ENAME             SAL       TOP3
    ---------- ---------- ---------- ----------
            10 KING             5000          1
               CLARK            2450          2
               MILLER           1300          3

            20 SCOTT            3000          1
               FORD             3000          2
               JONES            2975          3

            30 BLAKE            2850          1
               ALLEN            1600          2
               TURNER           1500          3

    9 rows selected.
    该查询根据工资列以降序排列各个划分(或分组,属于该deptno),并在处理过程中为每行分配一个顺序号。然后使用WHERE语句得到各划分的 前三行。
    Example 2例2:我需要工资为前三位的销售人员名字——即查找工资金额、排序、取最高的三项金额、给我领取这些工资的人员的名字。
    SELECT * FROM (
      SELECT deptno, ename, sal,
             DENSE_RANK()
      OVER (
        PARTITION BY deptno ORDER BY sal desc
      ) TopN FROM emp
    )
    WHERE TopN <= 3
    ORDER BY deptno, sal DESC
    /
    DEPTNO ENAME             SAL       TOPN
    ---------- ---------- ---------- ----------
            10 KING             5000          1
               CLARK            2450          2
               MILLER           1300          3

            20 SCOTT            3000          1  <--- !
               FORD             3000          1  <--- !
               JONES            2975          2
               ADAMS            1100          3

            30 BLAKE            2850          1
               ALLEN            1600          2
            30 TURNER           1500          3
    10 rows selected.
    其中,使用DENSE_RANK函数得出最高的三个工资金额。然后指定Dense rank至工资列,并将其按降序排列。 DENSE_RANK函数计算排序后分组中各行的序数。序数为从1开始的连续整数。最大的序数就是查询所所返回唯一值的个数。如果出现并列,序数不跳计。 具有相同值的列的序数相同。 DENSE_RANK函数不跳计序数,并为相同值的列赋予相同的序数。结果集合在当前窗口建立后,通过部门编号选择Dense rank为3 或3之前的行,就可以知道工资在该部门前三位的名字。

    Windows窗口:
    窗口语句用以定义滑动或固定数据窗口。在其上面运行组的分析函数。默认窗口为固定窗口,从第一行开始到当前行。可根据两种规则对窗口进行设置:数 据值的范围或当前行指定区距的行。分析函数中的ORDER BY会默认添加一条窗口语句:RANGE UNBOUNDED PRECEDING。即按照ORDER BY语句取得划分中的当前之前的所有行。以下例子为一个分组中的滑动窗口,计算该组中当前行与其前两行的SAL列的和。如我们需要计算当前员工的工资和其 之前的两人工资的和,如下例所示。
    SELECT deptno "Deptno", ename "Ename", sal "Sal",
      SUM(SAL)
        OVER (PARTITION BY deptno
              ORDER BY ename
              ROWS 2 PRECEDING) "Sliding Total"
    FROM emp
    ORDER BY deptno, ename
    /
    Deptno Ename     Sal Sliding Total
    ------ ------ ------ -------------
        10 CLARK    2450          2450
           KING     5000          7450
           MILLER   1300          8750

        20 ADAMS    1100          1100
           FORD     3000          4100
    JONES    2975          7075  ^
           SCOTT    3000          8975  |
           SMITH     800          6775  \-- Sliding Window

        30 ALLEN    1600          1600
           BLAKE    2850          4450
           JAMES     950          5400
           MARTIN   1250          5050
           TURNER   1500          3700
           WARD     1250          4000
    划分语句使SUM (sal)在各部门内进行,并独立于其他组。当部门改变时,SUM (sal) 也被“重置”。ORDER BY ENAME语句通过ENAME排列各部门的数据。这使得窗口语句:ROWS 2 PRECEDING获取该分组中当前行之前两行的数据以计算合计工资。
    例如,SMITH的SLIDING TOTAL(滑动合计)6 7 7 5是800、3000以及2975的和。即窗口中SMITH行及其之前两行工资的简单相加。
    Range Windows范围窗口:
         范围窗口根据WHERE语句对行进行收集。例如“之前5”将会生成一个滑动视窗,包括该分组中当前行之前的5个单位所有行。这些单位可以是数值或日期,使 用数字或日期以外的其他数据类型表示的范围无效。
    Example例:计算当前雇佣日期之前100天内雇佣的员工的数量。范围窗口返回当前行雇佣日期100天之前并在这个范围内计算行数。计算使用 以下窗口规格:
    COUNT(*) OVER (ORDER BY hiredate ASC RANGE 100 PRECEDING)
    SELECT ename, hiredate, hiredate-100 hiredate_pre,
           COUNT(*)
           OVER (
              ORDER BY hiredate ASC
              RANGE 100 PRECEDING
           ) cnt
      FROM emp
    ORDER BY hiredate ASC
    /
    Name     Hired      Hired-100  Cnt
    -------- ---------- ---------- ---
    SMITH    17-DEC-80  08-SEP-80    1
    ALLEN    20-FEB-81  12-NOV-80    2
    WARD     22-FEB-81  14-NOV-80    3
    JONES    02-APR-81  23-DEC-80    3
    LAKE    01-MAY-81  21-JAN-81    4
    CLARK    09-JUN-81  01-MAR-81    3
    TURNER   08-SEP-81  31-MAY-81    2
    MARTIN   28-SEP-81  20-JUN-81    2
    KING     17-NOV-81  09-AUG-81    3
    JAMES    03-DEC-81  25-AUG-81    5
    FORD     03-DEC-81  25-AUG-81    5
    MILLER   23-JAN-82  15-OCT-81    4
    SCOTT    09-DEC-82  31-AUG-82    1
    ADAMS    12-JAN-83  04-OCT-82    2
      根据雇佣日期ASC对每个划分进行排序。例中CLARK行可看到其雇佣日期为1981年6月9日,100天之前是1981年3月1日,看看在这期间雇佣的 员工,会发现JONES(雇佣日期:1981年4月2日)、BLAKE(雇佣日期:1981年5月1日),共3行,包括当前行,在CLARK行“Cnt” 列中。
    Compute average salary for defined range计算定义范围的平均工资:
    ,计算每个员工雇佣之前100天内雇佣员工的平均工资。查询如下:
    SELECT ename, hiredate, sal,
    AVG(sal)
           OVER (
              ORDER BY hiredate ASC
              RANGE 100 PRECEDING
           ) avg_sal
      FROM emp
    ORDER BY hiredate ASC
    /
    Name     Hired             SAL Avg-100
    -------- ---------- ---------- -------
    SMITH    17-DEC-80         800     800
    ALLEN    20-FEB-81        1600    1200
    WARD     22-FEB-81        1250    1217
    JONES    02-APR-81        2975    1942
    BLAKE    01-MAY-81        2850    2169
    CLARK    09-JUN-81        2450    2758
    TURNER   08-SEP-81        1500    1975
    MARTIN   28-SEP-81        1250    1375
    KING     17-NOV-81        5000    2583
    JAMES    03-DEC-81         950    2340
    FORD     03-DEC-81        3000    2340
    MILLER   23-JAN-82        1300    2563
    SCOTT    09-DEC-82        3000    3000
    ADAMS    12-JAN-83        1100    2050
    再看看CLARK,我们已知道他在本组中的范围窗口,可以看到平均工资2758由(2975+2850+2450)/3得来,是CLARK行和其 之前的JONES和BLAKE行工资的平均数。数据必须按由小到大顺序排列。
    Row Windows行窗口:
       行窗口为实际单位,是包括在窗口中实际行数。例如可以计算一给定记录的平均工资,该记录包括其之前或之后雇佣的员工(至多5名),具体如下:
    SELECT ename, hiredate, sal,
    AVG(sal)
      OVER (ORDER BY hiredate ASC ROWS 5 PRECEDING) AvgAsc,
    COUNT(*)
      OVER (ORDER BY hiredate ASC ROWS 5 PRECEDING) CntAsc,
    AVG(sal)
      OVER (ORDER BY hiredate DESC ROWS 5 PRECEDING) AvgDes,
    COUNT(*)
      OVER (ORDER BY hiredate DESC ROWS 5 PRECEDING) CntDes
    FROM emp
    ORDER BY hiredate
    /
    ENAME      HIREDATE    SAL AVGASC CNTASC AVGDES CNTDES
    ---------- --------- ----- ------ ------ ------ ------
    SMITH      17-DEC-80   800    800      1   1988      6
    ALLEN      20-FEB-81  1600   1200      2   2104      6
    WARD       22-FEB-81  1250   1217      3   2046      6
    JONES      02-APR-81  2975   1656      4   2671      6
    BLAKE      01-MAY-81  2850   1895      5   2675      6
    CLARK      09-JUN-81  2450   1988      6   2358      6
    TURNER     08-SEP-81  1500   2104      6   2167      6
    MARTIN     28-SEP-81  1250   2046      6   2417      6
    KING       17-NOV-81  5000   2671      6   2392      6
    JAMES      03-DEC-81   950   2333      6   1588      4
    FORD       03-DEC-81  3000   2358      6   1870      5
    MILLER     23-JAN-82  1300   2167      6   1800      3
    SCOTT      09-DEC-82  3000   2417      6   2050      2
    ADAMS      12-JAN-83  1100   2392      6   1100      1
    .该窗口中包括6行,现有行及此行“之前”的5行,其中“之前”由ORDER BY语句定义。对于ROW(行)的划分,不受RANGE(范围)划分的限制——数据可以是任何类型,order by可包括许多列。注意,也要选择COUNT(*),可以说明是多少行的平均值。从ALLEN记录可以清楚看到,他之前雇佣员工平均工资的计算使用了2个 记录,他之后雇佣员工平均工资的计算使用了6个记录。
    LAG(hiredate,1,NULL)
    OVER (PARTITION BY deptno
            ORDER BY hiredate, ename) last_hire,
    hiredate - LAG(hiredate,1,NULL)
      OVER (PARTITION BY deptno
            ORDER BY hiredate, ename) days_last,
    LEAD(hiredate,1,NULL)
      OVER (PARTITION BY deptno
            ORDER BY hiredate, ename) next_hire,
    LEAD(hiredate,1,NULL)
      OVER (PARTITION BY deptno
            ORDER BY hiredate, ename) - hiredate days_next
    FROM emp
    ORDER BY deptno, hiredate
    /
    Dep Ename  Hired     LastHired DaysLast NextHire  NextDays
    --- ------ --------- --------- -------- --------- --------
    10 CLARK   09-JUN-81                17-NOV-81        161
        KING   17-NOV-81 09-JUN-81     161 23-JAN-82     67
        MILLER 23-JAN-82 17-NOV-81     67

    20 SMITH   17-DEC-80                 02-APR-81        106
        JONES  02-APR-81 17-DEC-80      106 03-DEC-81     245
        FORD   03-DEC-81 02-APR-81      245 09-DEC-82     371
        SCOTT  09-DEC-82 03-DEC-81      371 12-JAN-83      34
        ADAMS  12-JAN-83 09-DEC-82      34
    30 ALLEN   20-FEB-81                 22-FEB-81         2
        WARD   22-FEB-81 20-FEB-81       2 01-MAY-81       68
        BLAKE  01-MAY-81 22-FEB-81       68 08-SEP-81      130
        TURNER 08-SEP-81 01-MAY-81       130 28-SEP-81     20
        MARTIN 28-SEP-81 08-SEP-81       20 03-DEC-81      66
        JAMES  03-DEC-81 28-SEP-81        66
    LEAD和LAG例程可看作对分组进行索引。使用这些函数可以访问任何一行。上面例子表明KING记录包括之前一行(上一雇佣)和下一行(下一) 中的数据(加粗红色字体)。可以很容易的访问排序后的分组中当前记录之前或之后记录中的字段。
    LAG
    LAG ( value_expr [, offset] [, default] )
       OVER ( [query_partition_clause] order_by_clause )
    . LAG无须自合并就可以获取同一个表格中的多行记录。知道来自查询中的多行以及光标的位置,LEAD就可以进入位置指定区距之前的行。
    如果不指定区距,默认值为1。如果区距超出窗口范围,则返回可指定默认值。如不指定默认值,则默认值为null。
    EMP表中的每个人之前雇佣员工的:

    SELECT ename,hiredate,sal,
    LAG(sal, 1, 0)
      OVER (ORDER BY hiredate) AS PrevSal
    FROM emp
    WHERE job = 'CLERK';
    Ename  Hired       SAL PREVSAL
    ------ --------- ----- -------
    SMITH  17-DEC-80   800       0
    JAMES  03-DEC-81   950     800
    MILLER 23-JAN-82  1300     950
    ADAMS  12-JAN-83  1100    1300
    LEAD
    LEAD ( value_expr [, offset] [, default] )
       OVER ( [query_partition_clause] order_by_clause )


    LEAD不用自合并就可同时进入一个表格中的多行。知道来自查询中的多行以及光标的位置,LEAD就可以进入位置指定区距之后的行。
    如不指定区距,则默认值为1。如区距超出窗口范围则返回任意默认值。如不指定默认值,默认值为0。
    例,EMP表中的每个员工,他们之后雇佣员工的雇佣日期:
    SELECT ename, hiredate,
    LEAD(hiredate, 1)
      OVER (ORDER BY hiredate) AS NextHired
    FROM emp WHERE deptno = 30;
    Ename  Hired     NEXTHIRED
    ------ --------- ---------
    ALLEN  20-FEB-81 22-FEB-81
    WARD   22-FEB-81 01-MAY-81
    BLAKE  01-MAY-81 08-SEP-81
    TURNER 08-SEP-81 28-SEP-81
    MARTIN 28-SEP-81 03-DEC-81
    JAMES  03-DEC-81
    Determine the First Value / Last Value of a Group确定组中的第一个值/最后一个值:
    FIRST_VALUE与LAST_VALUE函数可以选择一组中的第一行和最后一行。这些行很有用,因为它们经常用作计算的基线。
    Example例:例为每个部门的每名员工、最高工资员工的姓名。
    SELECT deptno, ename, sal,
      FIRST_VALUE(ename)
      OVER (PARTITION BY deptno
            ORDER BY sal ASC) AS MIN_SAL_HAS
    FROM emp
    ORDER BY deptno, ename;
        DEPTNO ENAME             SAL MIN_SAL_HAS

    ---------- ---------- ---------- -----------
            10 CLARK            2450 MILLER
               KING             5000 MILLER
               MILLER           1300 MILLER

            20 ADAMS            1100 SMITH
               FORD             3000 SMITH
               JONES            2975 SMITH
               SCOTT            3000 SMITH
               SMITH             800 SMITH

            30 ALLEN            1600 JAMES
               BLAKE            2850 JAMES
               JAMES             950 JAMES
               MARTIN           1250 JAMES
         TURNER           1500 JAMES
         WARD             1250 JAMES
    下例中为每个部门的每名员工、最高工资员工的姓名。
    SELECT deptno, ename, sal,
      FIRST_VALUE(ename)
      OVER (PARTITION BY deptno
            ORDER BY sal DESC) AS MAX_SAL_HAS
    FROM emp
    ORDER BY deptno, ename;
        DEPTNO ENAME             SAL MAX_SAL_HAS
    ---------- ---------- ---------- -----_-----
            10 CLARK            2450 KING
               KING             5000 KING
               MILLER           1300 KING
            20 ADAMS            1100 FORD
               FORD             3000 FORD
               JONES            2975 FORD
               SCOTT            3000 FORD
               SMITH             800 FORD
            30 ALLEN            1600 BLAKE
               BLAKE            2850 BLAKE
               JAMES             950 BLAKE
               MARTIN           1250 BLAKE
               TURNER           1500 BLAKE
               WARD             1250 BLAKE
    下例为第30个部门中的每名员工、工资最低员工的姓名,使用内联视图。
    SELECT deptno, ename, sal,
      FIRST_VALUE(ename)
      OVER (ORDER BY sal ASC) AS MIN_SAL_HAS
    FROM (SELECT * FROM emp WHERE deptno = 30)
        DEPTNO ENAME             SAL MIN_SAL_HAS
    ---------- ---------- ---------- -----------
            30 JAMES             950 JAMES
               MARTIN           1250 JAMES
               WARD             1250 JAMES
               TURNER           1500 JAMES
               ALLEN            1600 JAMES
               BLAKE            2850 JAMES
    交叉表查询,或者pivot查询,用稍微不同的方法将这些数据分组。交叉表查询可根据三行(一行代表一个项目),每行有三列(第一列列出项目,然 后一列代表一年)得出结果——如下:
    Example例:
    如果需要以列的形式显示每个部门中工资最多的3个人,查询为每个部门返回一行,一行有4列。DEPTNO,该部门中工资最高的人,工资第二高人的 名字,依次类推。使用分析函数很容易做到,不采用有分析函数这将是不可能的。
    SELECT deptno,
      MAX(DECODE(seq,1,ename,null)) first,
      MAX(DECODE(seq,2,ename,null)) second,
      MAX(DECODE(seq,3,ename,null)) third
    FROM (SELECT deptno, ename,
           row_number()
           OVER (PARTITION BY deptno
                 ORDER BY sal desc NULLS LAST) seq
           FROM emp)
    WHERE seq <= 3
    GROUP BY deptno
    /
        DEPTNO FIRST      SECOND     THIRD
    ---------- ---------- ---------- ----------
            10 KING       CLARK      MILLER
            20 SCOTT      FORD       JONES
            30 BLAKE      ALLEN      TURNER
    注意内查询,它按照工资高低根据部门为每名员工赋予一个序列(RowNr)。

    SELECT deptno, ename, sal,
    row_number()
    OVER (PARTITION BY deptno
           ORDER BY sal desc NULLS LAST) RowNr
    FROM emp;
    DEPTNO ENAME  SAL ROWNR
    ---------- ---------- ---------- ----------
    10 KING             5000          1
    10 CLARK            2450          2
    10 MILLER           1300          3
    20 SCOTT            3000          1
    20 FORD             3000          2
    20 JONES            2975          3
    20 ADAMS            1100          4
    20 SMITH             800          5
    30 BLAKE            2850          1
    30 ALLEN            1600          2
    30 TURNER           1500          3
    30 WARD             1250         4
    30 MARTIN           1250          5
    30 JAMES             950          6

    外查询中DECODE只保留含有序列1、2或3的记录行,并将它们分派到正确的“列”。GROUP BY去掉多余行,只剩下压缩结果。如果没有根据deptno分组的合计函数MAX,结果会更容易理解。
    SELECT deptno,
      DECODE(seq,1,ename,null) first,
      DECODE(seq,2,ename,null) second,
      DECODE(seq,3,ename,null) third
    FROM (SELECT deptno, ename,
           row_number()
           OVER (PARTITION BY deptno
                 ORDER BY sal desc NULLS LAST) seq
           FROM emp)
    WHERE seq <= 3
    /
        DEPTNO FIRST      SECOND     THIRD
    ---------- ---------- ---------- ----------
            10 KING
            10            CLARK
            10                       MILLER
            20 SCOTT
            20            FORD
            20                       JONES
            30 BLAKE
            30            ALLEN
            30                       TURNER
    通过GROUP BY列DEPTNO(按DEPTNO分组列)应用MAX合计函数。在上面任意给出的DEPTNO中,只有一行将对FIRST有非null值,其余行将永远 是NULL。MAX函数将选出非NULL值并保存。因此,group by和MAX将会压缩结果集,去掉NULL值并给出我们想要的值。

  • 相关阅读:
    结对项目黄金点游戏(邓乐&曾亮)
    软件工程个人项目:一个能自动生成小学四则运算的程序
    IE7下面zindex失效的问题
    参加一战到底有感
    Javascript中的prototype
    浏览器的页面渲染
    使用document.domain实现ajax跨子域
    PHP模拟http请求
    六天带你了解活动营销之第一天营销活动形式多样化
    jQuery源码学习第一天jQuery框架学习
  • 原文地址:https://www.cnblogs.com/oldcat/p/2153520.html
Copyright © 2020-2023  润新知