如果你在一个已经排序的CTE上做一个简单的SELECT-WHERE,你的结果是否保证仍然是相同的顺序,只是被过滤了?

问题描述 投票:0回答:1

想知道对于基于排序CTE的查询,Oracle 11g的期望deterministic排序输出。

考虑一下这个(为了极度简化的缘故)SQL查询示例。同样,注意CTE如何有一个 ORDER BY 子句。

WITH SortedArticles as (
    SELECT.  *
    FROM     Articles
    ORDER BY DatePublished
)
SELECT *
FROM   SortedArticles
WHERE  Author = 'Joe';

是否可以假设输出的行保证与CTE的顺序相同,还是说我必须对它们进行第二次重新排序?

再次强调,这是一个极其简单的例子,但它包含了我所要求的重要部分。 它们是...

  1. 对CTE进行排序
  2. 最后 SELECT 语句只针对CTE进行选择,不选择其他内容(没有连接等),并且
  3. 最后 SELECT 语句只指定一个 WHERE 子句。这纯粹是一个过滤语句。
sql oracle plsql oracle11g common-table-expression
1个回答
2
投票

简而言之,答案是否定的。唯一的方法是 保证 订购时要有 ORDER BY 子句,但在这种情况下,不需要在CTE中对结果进行排序。但是在这种情况下,不需要在CTE中对结果进行排序。

然而,如果排序表达式很复杂,而且你 需要 在派生CTE中进行排序(例如,由于使用了 OFFSET/FETCHROWNUM),您可以根据原始CTE的排序标准,在其上添加一个行号字段,然后只需根据该行号对派生的CTE进行排序,从而简化后续的排序。对于您的例子。

WITH SortedArticles as (
    SELECT *,
           ROW_NUMBER() OVER (ORDER BY DatePublished) AS rn
    FROM Articles
)
SELECT *
FROM SortedArticles
WHERE Author = 'Joe'
ORDER BY rn

0
投票

不,结果并不能保证和子查询的顺序一样。从来没有,也不会有。你可能会观察到某种行为,特别是当CTE被具体化的时候,你可以尝试用优化器提示来影响这种行为,比如说 /*+ MATERIALIZE *//*+ INLINE */. 然而,查询优化器的行为还取决于数据量、IO v cpu速度,最重要的是取决于数据库版本。例如,Oracle 12.2引入了一个名为 "内存中游标持续时间Temp表 "的功能,它试图加快像你这样的查询,而不保留子查询中的顺序。

我赞同@Nick的建议,在子查询中增加一个行号字段。

© www.soinside.com 2019 - 2024. All rights reserved.