如果您在已排序的 CTE 上执行简单的 SELECT-WHERE,您的结果是否保证仍处于相同顺序,只是经过过滤?

If you do a simple SELECT-WHERE on a CTE that is already sorted, are your results guaranteed to still be in that same order, just filtered?

想知道 expected/deterministic 从 Oracle 11g 为基于排序的 CTE 的查询排序输出。

考虑这个(为方便起见而极其简化的)示例 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子句。纯属过滤语句。

不,不保证结果与子查询中的顺序相同。从来没有,永远不会。您可能会观察到某种行为,尤其是当 CTE 被具体化时,您可以尝试使用 /*+ MATERIALIZE *//*+ INLINE */ 等优化器提示来影响它。然而,查询优化器的行为还取决于数据量、IO v cpu 速度,最重要的是取决于数据库版本。例如,Oracle 12.2 引入了一个名为 "In-Memory Cursor Duration Temp Table" 的特性,它试图加速像您这样的查询,而不保留子查询中的顺序。

我赞同@Nick 在子查询中添加行号字段的建议。

简短的回答是否定的。 保证 排序的唯一方法是在外部查询中使用 ORDER BY 子句。但是在那种情况下不需要对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