首先我们来看一下ROWNUM:
含义解释:
1、rownum是oracle为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推。这是一个伪列,可以用于限制查询返回的总行数。
2、rownum不能以任何基表的名称作为前缀。
对于ROWNUM来说,通常我们可以使用的比较符是<和<=,不能单独的使用=、>、>=等比较运算符,其实我们可以这样简单的理解,oracle是找到第一条的记录添加序号1之后,才可以知道谁是第二条记录,然后添加序号2,以此类推。所以对于等于来说,是可以有例外的,就是rownum=1。
我们来看几个简单的演示:
scott@DB01> create table demo as selectdemono,ename,sal,comm,deptno from demo;
Table created.
scott@DB01> select rownum,t.* from demo t;
ROWNUM demoNOENAME SAL COMM DEPTNO
---------- ---------- ---------- ---------- --------------------
1 7369SMITH 800 20
2 7499ALLEN 1600 300 30
3 7521WARD 1250 500 30
4 7566JONES 2975 20
5 7654MARTIN 1250 1400 30
6 7698BLAKE 2850 30
7 7782CLARK 2450 10
8 7788SCOTT 3000 20
9 7839KING 5000 10
10 7844TURNER 1500 0 30
11 7876ADAMS 1100 20
12 7900JAMES 950 30
13 7902FORD 3000 20
14 7934MILLER 1300 10
14 rows selected.
scott@DB01> select rownum,demono,ename,sal from demowhere rownum<=3;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
1 7369SMITH 800
2 7499ALLEN 1600
3 7521WARD 1250
scott@DB01> select rownum,demono,ename,sal from demowhere rownum<3;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
1 7369SMITH 800
2 7499ALLEN 1600
scott@DB01> select rownum,demono,ename,sal from demowhere rownum=1;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
1 7369SMITH 800
scott@DB01> select rownum,demono,ename,sal from demowhere rownum=3;
no rows selected
scott@DB01> select rownum,demono,ename,sal from demowhere rownum>3;
no rows selected
如果我们想要查询结果集中的某一段范围的记录,比如5-10条的记录,该如何查询呢?很多开发人员把这样的需求称为分页
scott@DB01> select rownum,demono,ename,sal from demowhere rownum between 5 and 10;
no rows selected
上面是一个错误的例子,我们来看正确的写法,这里我们使用到了集合运算符minus(减法运算)
scott@DB01> select rownum,demono,ename,sal from demowhere rownum<=10
2 minus
3 select rownum,demono,ename,sal from demo whererownum<=4;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
5 7654MARTIN 1250
6 7698BLAKE 2850
7 7782CLARK 2450
8 7788SCOTT 3000
9 7839KING 5000
10 7844TURNER 1500
6 rows selected.
如果我们有这样一个需求,找到员工demo表中,薪水最高的前三名,如何来实现呢?在sql server中有标准的topn分析语句,不过不要放到oracle里来使用,不同的数据库还是有区别的。当然了,也许你会认为这个问题有歧义,是前三个人呢?还是薪水排在最高3位的人?因为薪水有可能是相同的,在这里我们就找前三个人,看下面的语句:
scott@DB01> select rownum,demono,ename,sal
2> from demo
3> where rownum<=3
4> order by sal desc;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
2 7499ALLEN 1600
3 7521WARD 1250
1 7369SMITH 800
这个语句从表面上来看好像是正确的,从demo表里查询数据,排序,最后利用rownum返回前三个人,但是我们看语句的执行结果显然是不正确的。对于oracle的语句,我们在执行的时候遵循top-down的顺序,或者我们可以说,语句按照顺序来执行。
当然也有个别例外:
scott@DB01> select deptno,sum(sal) from demo
2 group by deptno
3 having sum(sal)>=10000;
DEPTNO SUM(SAL)
---------- ----------
20 10875
scott@DB01> select deptno,sum(sal) from demo
2 having sum(sal)>=10000
3 group by deptno;
DEPTNO SUM(SAL)
---------- ----------
20 10875
对于前面排名的语句当然是有问题的。当第2行语句执行后,拿到表中所有的数据,第3行语句紧接着执行,就把最前面的三条记录取出来了(rownum是对查询结果添加序号),这个时候,再做排序,当然拿到的就是对前面三条记录排序的结果,如上所示。
正确的思路应该是,先做排序,再做条件筛选,也就是4行子句要在3行之前运行,如何来实现呢?在这里oracle借助了子查询,用oracle的标准表述叫做内联视图(inlineview),当然整个的sql就是oracle的top N分析语句的写法,我们来看例子:
scott@DB01> select rownumrank,t.*
2 from (select demono,ename,sal from demo order by sal desc) t
3 where rownum<=3;
RANK demoNOENAME SAL
---------- ---------- ---------- ----------
1 7839KING 5000
2 7788SCOTT 3000
3 7902FORD 3000
在这里,oracle其实对内部子查询做了优化处理,我们通常认为,简单子查询是内层查询先执行,然后传递结果给外层查询,然后外层查询再执行。
但是对于这个例子,如果demo表数据量很大的话,那么内层排序需要花的时间就会非常多。而实际上呢,oracle会知道外层查询需要的记录数,如本例中是3,
oracle在对内层查询排序时,并不是对demo表中的14条记录做完全的排序,根据算法,他只要找到sal最高的3条就可以了,其余的11条记录是没必要排序的,这就大大的节省了语句的执行时间。
如果想要得到排序后的某段数据,我们可以通过嵌套的方法来实现:
scott@DB01> selectt1.*
2 from (select rownum rank,t.*from (select demono,ename,sal from demo order by sal desc) t)t1
3 where rank>=3 and rank<=7;
RANK demoNOENAME SAL
---------- ---------- ---------- ----------
3 7788SCOTT 3000
4 7566JONES 2975
5 7698BLAKE 2850
6 7782CLARK 2450
7 7499ALLEN 1600
注:在前面两个例子中,我们使用到了oracle的top N分析,不过都是对整张表,或者整个结果集来说的。其实oracle对于类似的操作,提供了一套函数,我们称之为分析函数,分析函数对于数据做统计和分析是非常有帮助的,我们在下面只是举一个简单的小例子,如果你感兴趣可以看看
scott@DB01> select * from demo;
demoNOENAME SAL COMM DEPTNO
---------- ---------- ---------- ---------- ----------
7369SMITH 800 20
7499ALLEN 1600 300 30
7521WARD 1250 500 30
7566JONES 2975 20
7654MARTIN 1250 1400 30
7698BLAKE 2850 30
7782CLARK 2450 10
7788SCOTT 3000 20
7839KING 5000 10
7844TURNER 1500 0 30
7876ADAMS 1100 20
7900JAMES 950 30
7902FORD 3000 20
7934MILLER 1300 10
14 rows selected.
scott@DB01> break on deptno skip 1
scott@DB01> select *
2 from (select deptno,
3 ename,
4 sal,
5 dense_rank() over(partition by deptno order by sal desc) dr
6 from demo
7 )
8 wheredr<=3
9 order by deptno;
DEPTNOENAME SAL DR
---------- ---------- ---------- ----------
10KING 5000 1
CLARK 2450 2
MILLER 1300 3
20SCOTT 3000 1
FORD 3000 1
JONES 2975 2
ADAMS 1100 3
30BLAKE 2850 1
ALLEN 1600 2
TURNER 1500 3
10 rows selected.
scott@DB01> select * from (
2 select deptno,
3 ename,
4 sal,
5 row_number() over(partition by deptno order by sal desc) dr
6 from demo
7 )
8 wheredr<=3
9 order by deptno;
DEPTNOENAME SAL DR
---------- ---------- ---------- ----------
10KING 5000 1
CLARK 2450 2
MILLER 1300 3
20SCOTT 3000 1
FORD 3000 2
JONES 2975 3
30BLAKE 2850 1
ALLEN 1600 2
TURNER 1500 3
含义解释:
1、rownum是oracle为从查询返回的行的编号,返回的第一行分配的是1,第二行是2,依此类推。这是一个伪列,可以用于限制查询返回的总行数。
2、rownum不能以任何基表的名称作为前缀。
对于ROWNUM来说,通常我们可以使用的比较符是<和<=,不能单独的使用=、>、>=等比较运算符,其实我们可以这样简单的理解,oracle是找到第一条的记录添加序号1之后,才可以知道谁是第二条记录,然后添加序号2,以此类推。所以对于等于来说,是可以有例外的,就是rownum=1。
我们来看几个简单的演示:
scott@DB01> create table demo as selectdemono,ename,sal,comm,deptno from demo;
Table created.
scott@DB01> select rownum,t.* from demo t;
ROWNUM demoNOENAME SAL COMM DEPTNO
---------- ---------- ---------- ---------- --------------------
1 7369SMITH 800 20
2 7499ALLEN 1600 300 30
3 7521WARD 1250 500 30
4 7566JONES 2975 20
5 7654MARTIN 1250 1400 30
6 7698BLAKE 2850 30
7 7782CLARK 2450 10
8 7788SCOTT 3000 20
9 7839KING 5000 10
10 7844TURNER 1500 0 30
11 7876ADAMS 1100 20
12 7900JAMES 950 30
13 7902FORD 3000 20
14 7934MILLER 1300 10
14 rows selected.
scott@DB01> select rownum,demono,ename,sal from demowhere rownum<=3;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
1 7369SMITH 800
2 7499ALLEN 1600
3 7521WARD 1250
scott@DB01> select rownum,demono,ename,sal from demowhere rownum<3;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
1 7369SMITH 800
2 7499ALLEN 1600
scott@DB01> select rownum,demono,ename,sal from demowhere rownum=1;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
1 7369SMITH 800
scott@DB01> select rownum,demono,ename,sal from demowhere rownum=3;
no rows selected
scott@DB01> select rownum,demono,ename,sal from demowhere rownum>3;
no rows selected
如果我们想要查询结果集中的某一段范围的记录,比如5-10条的记录,该如何查询呢?很多开发人员把这样的需求称为分页
scott@DB01> select rownum,demono,ename,sal from demowhere rownum between 5 and 10;
no rows selected
上面是一个错误的例子,我们来看正确的写法,这里我们使用到了集合运算符minus(减法运算)
scott@DB01> select rownum,demono,ename,sal from demowhere rownum<=10
2 minus
3 select rownum,demono,ename,sal from demo whererownum<=4;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
5 7654MARTIN 1250
6 7698BLAKE 2850
7 7782CLARK 2450
8 7788SCOTT 3000
9 7839KING 5000
10 7844TURNER 1500
6 rows selected.
如果我们有这样一个需求,找到员工demo表中,薪水最高的前三名,如何来实现呢?在sql server中有标准的topn分析语句,不过不要放到oracle里来使用,不同的数据库还是有区别的。当然了,也许你会认为这个问题有歧义,是前三个人呢?还是薪水排在最高3位的人?因为薪水有可能是相同的,在这里我们就找前三个人,看下面的语句:
scott@DB01> select rownum,demono,ename,sal
2> from demo
3> where rownum<=3
4> order by sal desc;
ROWNUM demoNOENAME SAL
---------- ---------- ---------- ----------
2 7499ALLEN 1600
3 7521WARD 1250
1 7369SMITH 800
这个语句从表面上来看好像是正确的,从demo表里查询数据,排序,最后利用rownum返回前三个人,但是我们看语句的执行结果显然是不正确的。对于oracle的语句,我们在执行的时候遵循top-down的顺序,或者我们可以说,语句按照顺序来执行。
当然也有个别例外:
scott@DB01> select deptno,sum(sal) from demo
2 group by deptno
3 having sum(sal)>=10000;
DEPTNO SUM(SAL)
---------- ----------
20 10875
scott@DB01> select deptno,sum(sal) from demo
2 having sum(sal)>=10000
3 group by deptno;
DEPTNO SUM(SAL)
---------- ----------
20 10875
对于前面排名的语句当然是有问题的。当第2行语句执行后,拿到表中所有的数据,第3行语句紧接着执行,就把最前面的三条记录取出来了(rownum是对查询结果添加序号),这个时候,再做排序,当然拿到的就是对前面三条记录排序的结果,如上所示。
正确的思路应该是,先做排序,再做条件筛选,也就是4行子句要在3行之前运行,如何来实现呢?在这里oracle借助了子查询,用oracle的标准表述叫做内联视图(inlineview),当然整个的sql就是oracle的top N分析语句的写法,我们来看例子:
scott@DB01> select rownumrank,t.*
2 from (select demono,ename,sal from demo order by sal desc) t
3 where rownum<=3;
RANK demoNOENAME SAL
---------- ---------- ---------- ----------
1 7839KING 5000
2 7788SCOTT 3000
3 7902FORD 3000
在这里,oracle其实对内部子查询做了优化处理,我们通常认为,简单子查询是内层查询先执行,然后传递结果给外层查询,然后外层查询再执行。
但是对于这个例子,如果demo表数据量很大的话,那么内层排序需要花的时间就会非常多。而实际上呢,oracle会知道外层查询需要的记录数,如本例中是3,
oracle在对内层查询排序时,并不是对demo表中的14条记录做完全的排序,根据算法,他只要找到sal最高的3条就可以了,其余的11条记录是没必要排序的,这就大大的节省了语句的执行时间。
如果想要得到排序后的某段数据,我们可以通过嵌套的方法来实现:
scott@DB01> selectt1.*
2 from (select rownum rank,t.*from (select demono,ename,sal from demo order by sal desc) t)t1
3 where rank>=3 and rank<=7;
RANK demoNOENAME SAL
---------- ---------- ---------- ----------
3 7788SCOTT 3000
4 7566JONES 2975
5 7698BLAKE 2850
6 7782CLARK 2450
7 7499ALLEN 1600
注:在前面两个例子中,我们使用到了oracle的top N分析,不过都是对整张表,或者整个结果集来说的。其实oracle对于类似的操作,提供了一套函数,我们称之为分析函数,分析函数对于数据做统计和分析是非常有帮助的,我们在下面只是举一个简单的小例子,如果你感兴趣可以看看
scott@DB01> select * from demo;
demoNOENAME SAL COMM DEPTNO
---------- ---------- ---------- ---------- ----------
7369SMITH 800 20
7499ALLEN 1600 300 30
7521WARD 1250 500 30
7566JONES 2975 20
7654MARTIN 1250 1400 30
7698BLAKE 2850 30
7782CLARK 2450 10
7788SCOTT 3000 20
7839KING 5000 10
7844TURNER 1500 0 30
7876ADAMS 1100 20
7900JAMES 950 30
7902FORD 3000 20
7934MILLER 1300 10
14 rows selected.
scott@DB01> break on deptno skip 1
scott@DB01> select *
2 from (select deptno,
3 ename,
4 sal,
5 dense_rank() over(partition by deptno order by sal desc) dr
6 from demo
7 )
8 wheredr<=3
9 order by deptno;
DEPTNOENAME SAL DR
---------- ---------- ---------- ----------
10KING 5000 1
CLARK 2450 2
MILLER 1300 3
20SCOTT 3000 1
FORD 3000 1
JONES 2975 2
ADAMS 1100 3
30BLAKE 2850 1
ALLEN 1600 2
TURNER 1500 3
10 rows selected.
scott@DB01> select * from (
2 select deptno,
3 ename,
4 sal,
5 row_number() over(partition by deptno order by sal desc) dr
6 from demo
7 )
8 wheredr<=3
9 order by deptno;
DEPTNOENAME SAL DR
---------- ---------- ---------- ----------
10KING 5000 1
CLARK 2450 2
MILLER 1300 3
20SCOTT 3000 1
FORD 3000 2
JONES 2975 3
30BLAKE 2850 1
ALLEN 1600 2
TURNER 1500 3