最近在解决一个项目的用户管理模块的问题时,由于改动了查询条件,发现分页出现了问题。刚开始以为是封装的分页标签有问题,进过调试,发现分页的参数都是正确的!于是把Sql语句打印出来在数据库调试时,发现了一个奇怪的问题:条件一样的sql语句加上rownum<=40和rownum<=60时,竟然前40条的数据不一样。我就纳闷了,然后再网上查询了下rownum的原理:rownum它是oracle系统顺序分配为从查询返回的行的编号。那么oracle在编rownum时,sql语句的执行过程是什么样的呢?
比分说select * from (select * from a where a.name like '%1%' ) where rownum < 3经实际分析发现:
流程应该是这样的:
1.先执行select * from a where a.name like '%1%' 的条件查询出结果并生成结果集
2.给第一步生成的结果集加上rownum伪列
3.按照rownum的条件进一步限制。如果一条记录不符合rownum的限制条件,则丢弃,而且下一条记录的rownum还是从1开始重新计数
在对照我的sql语句,我发现我的多了一个order by条件 那么在上面的sql语句上加上order by条件后sql语句的rownum编号是如何进行的呢?
sql:select * from (select * from a where a.name like '%1%' order by name ) where rownum < =40
经测试发现流程应该是这样的:
1.先执行select * from a where a.name like '%1%' 的条件查询出结果并生成结果集
2.给第一步生成的结果集加上rownum伪列
3.在加上rownum的结果集上面进行order by排序后输出新的结果集
4.按照rownum的条件进一步限制。如果一条记录不符合rownum的限制条件,则丢弃,而且下一条记录的rownum还是从1开始重新计数。
所以下面的2条sql:
sql1:select * from ( select * from (select * from a where a.name like '%1%' order by name ) where rownum < =40 ) where rownum > 20
sql2:select * from ( select * from (select * from a where a.name like '%1%' order by name ) where rownum <=60 ) where rownum > 40
就知道了问题出在了上面地方:在我的排序字段上,由于排序的字段name有重复的,所以就出现了上面的问题,解决的方法很简单,把排序的条件换成唯一的就可以了。比如说 order by userId
参考:http://hi.baidu.com/heqinghua/item/9ce8a13a54c9168df4e4ad48
http://www.cnblogs.com/zjrstar/archive/2006/08/31/491090.html