2016-12-27 88 views
1

我对所有的常见问题及的HOWTOs建议Oracle数据库的规范前N个查询:rownum的订单 - 它是否正确?

select ... from (
    select ... from ... order by ... 
) where ronwum <= N 

它完美对甲骨文11,即它在内部选择指定的顺序返回前N个记录。

然而,它在Oracle 12上打破了。它仍然返回相同的top-N记录,但它们可能会被混洗。这些记录的最终顺序是非确定性的。

我使用Google搜索,但没有找到任何相关的讨论。看起来其他人总是从这样的选择中获得正确的记录顺序。

虽然有一个发现很有趣。我看到一些人使用(不解释,可惜)外的额外order by rownum条款选择:

select ... from (
    select ... from ... order by ... 
) where ronwum <= N 
order by rownum 

(包括ROWNUM在这里是对Oracle虚列引用,它是由内选择返回的东西)

它似乎工作。但是使用Oracle优化器,您永远无法确定它是否只是运气或者真正正确的解决方案。

问题是:order by rownum在这种情况下是否保证正确的排序顺序,为什么?我和我的同事们无法就此达成一致。

P.S.我知道其他的方式来选择前N个记录,例如使用row_number解析函数和Oracle 12中引入的fetch first子句。我也知道,我可以在外层select上重复相同的order by ...。问题仅在于order by rownum - 是否正确。

+3

我认为你需要重命名'rownum'的东西在内部不同select,否则外部引用引用rownum作为外部查询,而不引用内部查询。 –

+1

执行此操作的正确方法是按外部查询中的相同表达式进行排序,就像您在子查询中所做的那样。即使在Oracle 11和之前的版本中,从内部查询到外部查询的顺序被保留的事实也是一个实现意外事件 - 它不能保证SQL标准。 – mathguy

回答

-1

内部查询和外部查询可能会或可能不会给出不同的顺序,因此rownum的顺序也不同。由于rownum已经订购了,如果你想获得最好的N条记录,那么最好的办法是在内部查询中创建rownum的别名,并在外部查询中使用它。

选择...从( 选择ROWNUM RN从〜 ),其中RN < = N 为了RN上

+1

这是行不通的,因为rownum是在订购之前分配的。这个查询会给出N个完全随机的行。 重写查询不是问题的关键。 – Alexey