【SQL】获取指定范围内结果集的实现方法

Web应用经常会出现分页显示结果集的场景,如果处理不好将会严重影响应用程序的性能。如何突破这个瓶颈呢?
通过一个需求演示场景给大家展示两种实现方法,孰优孰劣看后便知。

1.创建实验表T,并初始化一些实验数据
sec@ora10g> create table t (id number, sal number);
sec@ora10g> insert into t values (1,1000);
sec@ora10g> insert into t values (2,800);
sec@ora10g> insert into t values (3,600);
sec@ora10g> insert into t values (4,2000);
sec@ora10g> insert into t values (5,3000);
sec@ora10g> insert into t values (6,1500);
sec@ora10g> insert into t values (7,1800);
sec@ora10g> insert into t values (8,2100);
sec@ora10g> insert into t values (9,400);
sec@ora10g> insert into t values (10,600);
sec@ora10g> insert into t values (11,200);
sec@ora10g> insert into t values (12,1900);
sec@ora10g> insert into t values (13,3000);
sec@ora10g> insert into t values (14,4000);
sec@ora10g> commit;

2.T表数据概览
sec@ora10g> select * from t;

        ID        SAL
---------- ----------
         1       1000
         2        800
         3        600
         4       2000
         5       3000
         6       1500
         7       1800
         8       2100
         9        400
        10        600
        11        200
        12       1900
        13       3000
        14       4000

14 rows selected.

3.实现需求一:按照工资升序排序后的第1名到第3名信息
1)错误方法
sec@ora10g> select * from t where rownum<=3 order by sal;

        ID        SAL
---------- ----------
         3        600
         2        800
         1       1000

这种查询方法是先获得T表中的前三条记录,然后对这三条记录的sal值进行排序。与我们的需求不符。

2)正确方法一
使用子查询与rownum完成任务。
sec@ora10g> select * from (select * from t order by sal) where rownum<=3;

        ID        SAL
---------- ----------
        11        200
         9        400
         3        600

3)正确方法二
使用分析函数ROW_NUMBER完成此任务。
sec@ora10g> select id, sal
  2    from (select id, sal, ROW_NUMBER () over (order by sal) as rn
  3            from t)

  4   where rn <= 3;

        ID        SAL
---------- ----------
        11        200
         9        400
         3        600

4.实现需求二:按照工资升序排序后的第4名到第6名信息
1)错误的方法
sec@ora10g> select * from (select * from t order by sal) where rownum between 4 and 6;

no rows selected

rownum的这种使用方法是不正确的!要坚决抵制。

2)正确方法一
用rownum来构造这个结果集
sec@ora10g> select *
  2    from (select * from (select * from t order by sal)
  3           where ROWNUM <= 6
  4          minus
  5          select * from (select * from t order by sal)
  6           where ROWNUM <= 3)
  7  order by sal;

        ID        SAL
---------- ----------
        10        600
         2        800
         1       1000

可见,使用这种集合减构造出来的结果集的方法稍显笨重。

3)正确方法二
使用分析函数ROW_NUMBER可以很便捷的完成这个任务。
sec@ora10g> select id, sal
  2    from (select id, sal, ROW_NUMBER () over (order by sal) as rn
  3            from t)

  4   where rn between 4 and 6;

        ID        SAL
---------- ----------
        10        600
         2        800
         1       1000

5.以此类推,便可以实现任意指定范围内的统计数据查询。

6.小结
“正确方法一”给出的方法虽然可以实现我们的需求,但是获取数据的代价较大,其间存在大量的排序操作。
“正确方法二”使用分析函数先对第一种方法效率上得到了保证,同时给SQL的编写带来很大的灵活性,推荐使用。
通过这个例子我们再一次体会到了分析函数带给我们的便利和高效。

Good luck.

secooler
10.02.06

-- The End --

请使用浏览器的分享功能分享到微信等