查看: 2538|回复: 10

[PL/SQL] Oralce一个rownum的诡异问题。。

[复制链接]
论坛徽章:
0
跳转到指定楼层
1#
发表于 2012-5-14 17:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 inoracle 于 2012-5-14 17:54 编辑

在oracle进行查询前几条数据的时候,使用到了rownum,之前一直没有注意到一个小问题,今天无意发现了。
特拿出来请教各位,望各位高人能讨论给出关注和释惑:

句子很简单:
根据薪资sal降序排序,查出所有数据,这里使用了子查询对结果进行操作,外部查询输出了子查询结果的rownum,这个值在目前数据确定的情况下应该是固定的:
select  empno,ename,sal,rownum from
(select empno,ename,sal from emp where sal is not null order by sal desc)

   EMPNOENAMESALROWNUM
17839KING5000.001
27902FORD3000.002
37788SCOTT3000.003
47566JONES2975.004
57698BLAKE2850.005
67782CLARK2450.006
77499ALLEN1600.007
87844TURNER1500.008
97934MILLER1300.009
107521WARD1250.0010
117654MARTIN1250.0011
127369SMITH1120.0012
137876ADAMS1100.0013
147900JAMES950.0014


(注意前三条数据的顺序,这里是对子查询的数据再查询,所以rownum应该已经确定了)


现在我们给外部这个查询结果加上条件,取rownum<=3的,即刚的rownum为1,2,3的前三条数据(KING,FORD,SCOTT):
select  empno,ename,sal,rownum from
(select empno,ename,sal from emp where sal is not null order by sal desc)
where rownum<=3 order by rownum asc


EMPNOENAMESALROWNUM
7839KING5000.001
7788SCOTT3000.002
7902FORD3000.003



(注意:本来rownum为1,2,3的前三条数据为(KING,FORD,SCOTT),但是通过rownum<=3取出来之后,1,2,3对应的前三条数据为(KING,SOCTT,FORD)
)


很多人瞄一眼就会说rownum是不确定的,rowid才是确定的,这是非常潦草而没有认真思考的回答。
至少你应该回答当使用rownum做取前几条值的时候可能取完后会有自己新的排序方式。但是如果真的存在这样的问题(事实来看确实如此),就可能给我们取值带来不可预料的问题。不是吗,本来我们观测认为(或者希望)的前三条数据的顺序不该是(KING,FORD,SCOTT)吗???
所以,这绝对不是一个简单的rownum问题。

还望不吝赐教,以释疑惑。

论坛徽章:
484
ITPUB北京香山2007年会纪念徽章
日期:2007-01-24 14:35:02ITPUB北京九华山庄2008年会纪念徽章
日期:2008-01-21 16:50:24ITPUB北京2009年会纪念徽章
日期:2009-02-09 11:42:452010新春纪念徽章
日期:2010-03-01 11:04:552010数据库技术大会纪念徽章
日期:2010-05-13 10:04:272010系统架构师大会纪念
日期:2010-09-04 13:35:54ITPUB9周年纪念徽章
日期:2010-10-08 09:28:512011新春纪念徽章
日期:2011-02-18 11:43:32ITPUB十周年纪念徽章
日期:2011-11-01 16:19:412012新春纪念徽章
日期:2012-01-04 11:49:54
2#
发表于 2012-5-14 18:20 | 只看该作者
你的order by并没有明确确定2/3两条数据的顺序,所以你前后两个不同的sql是会出现差别
rownum作为限制条件有时候会改变执行计划的(STOP KEY),你将语句在你的数据库里的执行计划都贴出来看看

使用道具 举报

回复
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
3#
发表于 2012-5-14 19:20 | 只看该作者
排序的那两个sal都是3000,相同值的排序,结果是不确定的
你要钱不一样,不可能出现这问题

使用道具 举报

回复
论坛徽章:
407
紫蛋头
日期:2012-05-21 10:19:41迷宫蛋
日期:2012-06-06 16:02:49奥运会纪念徽章:足球
日期:2012-06-29 15:30:06奥运会纪念徽章:排球
日期:2012-07-10 21:24:24鲜花蛋
日期:2012-07-16 15:24:59奥运会纪念徽章:拳击
日期:2012-08-07 10:54:50奥运会纪念徽章:羽毛球
日期:2012-08-21 15:55:33奥运会纪念徽章:蹦床
日期:2012-08-21 21:09:51奥运会纪念徽章:篮球
日期:2012-08-24 10:29:11奥运会纪念徽章:体操
日期:2012-09-07 16:40:00
4#
发表于 2012-5-14 19:32 | 只看该作者
SQL> delete emp;

已删除7行。

已用时间:  00: 00: 00.00
SQL> commit;

提交完成。

已用时间:  00: 00: 00.00
SQL> insert into emp(ename,sal) values(1,5000);

已创建 1 行。

已用时间:  00: 00: 00.00
SQL> insert into emp(ename,sal) values(2,3000);

已创建 1 行。

已用时间:  00: 00: 00.00
SQL> insert into emp(ename,sal) values(3,3000);

已创建 1 行。

已用时间:  00: 00: 00.00
SQL> commit;

提交完成。

已用时间:  00: 00: 00.00
SQL> select  empno,ename,sal,rownum from
  2  (select empno,ename,sal from emp where sal is not null order by sal desc)
  3  /

     EMPNO ENAME             SAL     ROWNUM
---------- ---------- ---------- ----------
           1                5000          1
           2                3000          2
           3                3000          3

已用时间:  00: 00: 00.00
SQL> select  empno,ename,sal,rownum from
  2  (select empno,ename,sal from emp where sal is not null order by sal desc)
  3  where rownum<=3 order by rownum asc
  4  /

     EMPNO ENAME             SAL     ROWNUM
---------- ---------- ---------- ----------
           1                5000          1
           2                3000          2
           3                3000          3

已用时间:  00: 00: 00.00
SQL>

使用道具 举报

回复
论坛徽章:
1088
金色在线徽章
日期:2007-04-25 04:02:08金色在线徽章
日期:2007-06-29 04:02:43金色在线徽章
日期:2007-03-11 04:02:02在线时间
日期:2007-04-11 04:01:02在线时间
日期:2007-04-12 04:01:02在线时间
日期:2007-03-07 04:01:022008版在线时间
日期:2010-05-01 00:01:152008版在线时间
日期:2011-05-01 00:01:342008版在线时间
日期:2008-06-03 11:59:43ITPUB年度最佳技术原创精华奖
日期:2013-03-22 13:18:30
5#
发表于 2012-5-14 20:20 | 只看该作者
上面的例子说明不了什么,撸主第2个结果,也没有错误,不一定就非要和第一个结果一样的顺序,他完全符合你的sql结果要求

使用道具 举报

回复
论坛徽章:
519
奥运会纪念徽章:垒球
日期:2008-09-15 01:28:12生肖徽章2007版:鸡
日期:2008-11-17 23:40:58生肖徽章2007版:马
日期:2008-11-18 05:09:48数据库板块每日发贴之星
日期:2008-11-29 01:01:02数据库板块每日发贴之星
日期:2008-12-05 01:01:03生肖徽章2007版:虎
日期:2008-12-10 07:47:462009新春纪念徽章
日期:2009-01-04 14:52:28数据库板块每日发贴之星
日期:2009-02-08 01:01:03生肖徽章2007版:蛇
日期:2009-03-09 22:18:532009日食纪念
日期:2009-07-22 09:30:00
6#
发表于 2012-5-14 23:12 | 只看该作者
两个SQL不同,两个ROWNUM的顺序也可能不同,但它们都是对的,都满足楼主的条件。为了消除歧义就应该ORDER BY SAL DESC,ROWID

使用道具 举报

回复
论坛徽章:
0
7#
 楼主| 发表于 2012-5-15 11:58 | 只看该作者
dingjun123 发表于 2012-5-14 20:20
上面的例子说明不了什么,撸主第2个结果,也没有错误,不一定就非要和第一个结果一样的顺序,他完全符合你的 ...

数据重复的情况下,可能导致数据无法显示。请关注ORDER BY STOPKEY。

使用道具 举报

回复
论坛徽章:
0
8#
 楼主| 发表于 2012-5-15 11:59 | 只看该作者
newkid 发表于 2012-5-14 23:12
两个SQL不同,两个ROWNUM的顺序也可能不同,但它们都是对的,都满足楼主的条件。为了消除歧义就应该ORDER B ...

您是正解。但这样的语句如果不使用rowid,分页时可能将出现数据无法显示。

使用道具 举报

回复
论坛徽章:
0
9#
 楼主| 发表于 2012-5-15 12:04 | 只看该作者
dingjun123 发表于 2012-5-14 19:20
排序的那两个sal都是3000,相同值的排序,结果是不确定的
你要钱不一样,不可能出现这问题

所言正是

使用道具 举报

回复
论坛徽章:
0
10#
 楼主| 发表于 2012-5-15 12:04 | 只看该作者
lastwinner 发表于 2012-5-14 18:20
你的order by并没有明确确定2/3两条数据的顺序,所以你前后两个不同的sql是会出现差别
rownum作为限制条件 ...

感谢提示,正是如此,ORDER BY STOPKEY。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

TOP技术积分榜 社区积分榜 徽章 团队 统计 知识索引树 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛
CopyRight 1999-2011 itpub.net All Right Reserved. 北京盛拓优讯信息技术有限公司版权所有 联系我们 未成年人举报专区 
京ICP备16024965号-8  北京市公安局海淀分局网监中心备案编号:11010802021510 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表