Oracle 12c中文版数据库管理、应用与开发实践教程 (清华电脑学堂)
上QQ阅读APP看书,第一时间看更新

4.4 操作查询结果

使用SELECT语句查询数据时,可以对查询的结果进行排序、分组和统计。一旦为查询结果集进行了排序、分组或统计,就可以方便用户查询数据。

4.4.1 对查询结果排序

在前面介绍的数据检索技术中,只是把数据库中的数据从表中直接取出来。这时,结果集中数据的排列顺序是由数据的存储顺序决定的。但是,这种存储顺序经常不符合开发人员的查询要求。当查询一个比较大的表时,数据的显示会比较混乱,因此需要对检索到的结果集进行排序。

在SELECT语句中,使用ORDER BY子句实现对查询的结果集进行排序。排序有两种方式:ASC表示升序,这也是默认的排序方式;DESC表示降序。

【范例17】

查询emp表中的前三条记录,并且将对sal表进行升序排列。语句和输出结果如下。

        SELECT empno, ename, sal FROM emp WHERE ROWNUM<=3 ORDER BY sal;
        EMPNO       ENAME      SAL
        -------------------------
        7369        SMITH      800
        7521        WARD      1250
        7499        ALLEN     1600

将上述结果与范例16中的输出结果进行比较可以发现,ORDER BY关键字进行升序排序已经成功。

【范例18】

查询emp表中的前三条记录,并且将对sal表进行降序排列。语句和输出结果如下。

        SELECT empno, ename, sal FROM emp WHERE ROWNUM<=3 ORDER BY sal DESC;
        EMPNO          ENAME        SAL
        ----------  -----------   -------
        7499          ALLEN       1600
        7521          WARD        1250
        7369          SMITH        800

【范例19】

开发人员可以在ORDER BY子句中使用别名或表达式。例如,在SELECT子句中计算出员工的年薪并指定别名FULLYEARSAL,然后在ORDER BY子句中根据指定的别名进行降序排列。语句和输出结果如下。

      SELECT empno, ename, sal, (sal*12) FULLYEARSAL FROM emp WHERE ROWNUM<=3
      ORDERBY FULLYEARSAL DESC;
      EMPNO     ENAME         SAL      FULLYEARSAL
      -------  -----------  --------  -----------
      7499      ALLEN        1600       19200
      7521      WARD         1250       15000
      7369      SMITH         800        9600

【范例20】

如果需要对多个列进行排序,只需要在ORDER BY子句后指定多个列名。这样当输出排序结果时,首先根据第一列排序,当第一列的值相同时,再对第二列进行比较排序,其他列以此类推。

下面使用SELECT语句首先对sal列排序,然后再对ename列排序。代码如下。

        SELECT empno, ename, sal FROM emp WHERE ROWNUM<=3 ORDER BY sal DESC, ename;

4.4.2 对查询结果分组

GROUP BY子句用于在查询结果集中对记录进行分组,以汇总数据或者为整个分组显示单行的汇总信息。

开发人员在使用GROUP BY子句时,必须满足以下几个条件。

(1)在SELECT子句的后面只可以有两类表达式:聚合函数和进行分组的列名。

(2)在SELECT子句中的列名必须是进行分组的列,除此之外添加其他的列表都是错误的。但是GROUP BY子句后面的列名可以不出现在SELECT子句中。

(3)如果使用了WHERE子句,那么所有参数分组计算的数据必须首先满足WHERE子句指定的条件。

(4)在默认情况下,将按照GROUP BY子句指定的分组列升序排列,如果需要重新排序,可以使用ORDER BY子句指定新的排列顺序。

【范例21】

在使用GROUP BY子句之前首先查询emp表中的记录,并且针对job列和sal列排序,语句和输出结果如图4-4所示。从图4-4中可以看出,对于每一个job列,都可以有多个对应的sal值。

图4-4 查询emp表中的记录

开发人员可以使用GROUP BY子句实现对查询结果中每一组数据进行分类统计。使用GROUP BY子句时,在结果中每组数据都有一个与之对应的统计值。GROUP BY子句实现分组功能时,通常会用到聚合函数,关于聚合函数会在第8章中介绍。

【范例22】

使用GROUP BY子句对job列进行分组,并且分别使用COUNT()函数、SUM()函数、AVG()函数、MAX()函数和MIN()函数计算每个职位(job列)的数据行数、所有工资总和、平均工资、最高工资和最低工资。语句和输出结果如下。

        SELECT job, COUNT(job), SUM(sal), AVG(sal), MAX(sal), MIN(sal) FROM emp GROUP
        BYjob;
        JOB         COUNT(JOB)    SUM(SAL)    AVG(SAL)   MAX(SAL)   MIN(SAL)
        ---------  ------------  ----------   ----------  ---------   --------
        CLERK           4          4150        1037.5       1300         800
        SALESMAN        4          5600        1400         1600        1250
        PRESIDENT       1          5000        5000         5000        5000
        MANAGER         3          8275        2758.33333   2975        2450
        ANALYST         1          3000        3000         3000        3000

GROUP BY子句与ORDER BY子句很相似,GROUP BY子句也可以对多个列进行分组。在这种情况下,GROUP BY子句将在主分组范围内进行二次分组。

【范例23】

下面的语句对各部门中的各个工作类型进行分组。

      SELECT  deptno, job, COUNT(*), SUM(sal), AVG(sal)  FROM  emp  GROUP  BY
      deptno, job;

执行上述语句,输出结果如下。

        DEPTNO     JOB        COUNT(*)   SUM(SAL)       AVG(SAL)
        -------  -----------  ----------  ------------  --------------------
        20         CLERK         2           1900            950
        30         SALESMAN      4           5600            1400
        20         MANAGER       1           2975            2975
        30         CLERK         1           950             950
        10         PRESIDENT     1           5000            5000
        30         MANAGER       1           2850            2850
        10         CLERK         1           1300            1300
        10         MANAGER       1           2450            2450
        20         ANALYST       1           3000            3000

GROUP BY子句中可以使用ROLLUP和CUBE运算符,这两个运算符在功能上相似。在GROUP BY子句中使用它们后,都将会在查询结果中附加一行汇总信息。

【范例24】

下面的语句在GROUP BY中使用ROLLUP运算符汇总job列。

      SELECT job, COUNT(*), SUM(sal), AVG(sal) FROM emp GROUP BY ROLLUP(job);

执行上述语句,输出结果如下。

        JOB         COUNT(*)      SUM(SAL)        AVG(SAL)
        ----------  -------------  -------------  -------------
        ANALYST         1               3000            3000
        CLERK           4               4150          1037.5
        MANAGER         3               8275      2758.33333
        PRESIDENT       1               5000            5000
        SALESMAN        4               5600            1400
                        13              26025     2001.92308

试一试

当使用CUBE运算符时也会在查询结果中附加一行汇总信息,但是它不是在查询结果的底部(最后一行),而是顶部(第一行),感兴趣的读者可以亲自动手试一试。

4.4.3 对查询结果筛选

HAVING子句通常与GROUP BY子句一起使用,在完成对分组结果统计之后,可以使用HAVING子句对分组的结果做进一步筛选。如果不使用GROUP BY子句, HAVING子句的功能与WHERE子句一样。HAVING子句和WHERE子句的相似之处就是都定义搜索条件,但是和WHERE子句不同,不同点表现在以下三个方面。

(1)HAVING针对结果组;WHERE针对的是列的数据。

(2)HAVING可以与聚合函数一起使用;但是WHERE不能。

(3)HAVING语句只过滤分组后的数据;WHERE在分组前对数据进行过滤。

【范例25】

下面的语句查询工作类型的员工人数不等于1的记录。

        SELECT job, COUNT(*), SUM(sal), AVG(sal) FROM emp GROUP BY job HAVING
    COUNT(*)! =1;

执行上述语句,输出结果如下。

        JOB        COUNT(*)  SUM(SAL)  AVG(SAL)
        -----------------  --------------  ---------------  ---------------
        CLERK         4      4150        1037.5
        SALESMAN     4      5600        1400
        MANAGER      3      8275        2758.33333

从上述查询结果可以看出,SELECT语句使用GROUP BY子句对emp表进行分组统计,然后再由HAVING子句根据统计值做进一步筛选。

提示

通常情况下,HAVING子句与GROUP子句一起使用,这样可以在汇总相关数据后再进一步筛选汇总的数据。在使用WHERE子句或HAVING子句都能查询出相同的结果时, WHERE子句放在GROUP BY子句之前,而HAVING子句放在GROUP BY子句之后。