问题1:
针对如下这条SQL,使用了row_number()函数,但外层使用了rownum,
老虎刘老师指出,
这种写法又回到最初了,相当于没用分析函数。 应该是分析函数生成的列给个别名,然后外层再用这个别名<=10,而不是还用rownum<=10。 使用分析函数和rownum,两个逻辑不一样的SQL得到相同结果集,只能说是巧合。
归根结底,缺少对这个函数的理解,还是需要重新领悟下ROW_NUMBER(),他的定义如下,
ROW_NUMBER() OVER ([query_partition_clause] order_by_clause)
ROW_NUMBER()为查询出来的每一行记录生成一个序号,依次排序且不会重复,能用于实现top-N、bottom-N、inner-N,
ROW_NUMBER is an analytic function. It assigns a unique number to each row to which it is applied (either each row in the partition or each row returned by the query), in the ordered sequence of rows specified in the order_by_clause, beginning with 1. This use of the function lets you implement top-N, bottom-N, and inner-N reporting
这是《Reference》的示例,可以看出department_id相同的记录,别名是emp_id,会标记序号,而且按照employee_id的顺序进行排列,体现出ROW_NUMBER()的作用,
这个则是实现inner-N,返回按照last_name排序的51-100条记录,
相应地,针对我们的需求,改为如下SQL,将ronwum<=10改为row_number()<=10,而且注意个细节,即使内层查询,没有order by name desc将bbb排在aaa前面,此时使用t.c='aaa' OR t.c='bbb' AND t.e <= 10作为条件,并不会像《从一条"错误"的SQL,了解rownum的作用》中使用NAME='aaa' OR NAME='bbb' AND ROWNUM<=10作为条件,得到19条aaa和1条bbb,而是返回正确的19条aaa和10条bbb,
问题2:
有一位朋友说,
我想通过union all来实现,一个取符合要求的aaa,一个是取bbb,最后一合并,可以,虽然有点慢。但是这样是没有顺序的,但是,当我要order by rowid时候,就报了错(ORA 01446)。
他用的SQL如下,
ORA-01446的错误提示看,原因是无法从带distinct、group by的视图中检索ROWID,
01446, 00000, "cannot select ROWID from, or sample, a view with DISTINCT, GROUP BY, etc." // *Cause: // *Action:
我们从这条SQL,对应的执行计划,就能看出来,需要排序的是内层子查询视图的结果集,而视图的SELECT检索项中没有ROWID,所以根本不知道按照谁的ROWID进行排序,抛出错误ORA-01446,
因此,只需要在子查询中的SELECT,增加ROWID字段,外层就能按照ROWID,进行排序,
问题3:
将问题1和问题2,进行结合,还能解决name按照rowid排序的问题,
对应执行计划,如下所示,
P.S.
对于数据检索的顺序,多说一句,有时你看见的,未必是真相,可以参考《Oracle读取数据的顺序问题》中对数据检索顺序的探索。