想知道对于基于排序CTE的查询,Oracle 11g的期望deterministic排序输出。
考虑一下这个(为了极度简化的缘故)SQL查询示例。同样,注意CTE如何有一个 ORDER BY
子句。
WITH SortedArticles as (
SELECT. *
FROM Articles
ORDER BY DatePublished
)
SELECT *
FROM SortedArticles
WHERE Author = 'Joe';
是否可以假设输出的行保证与CTE的顺序相同,还是说我必须对它们进行第二次重新排序?
再次强调,这是一个极其简单的例子,但它包含了我所要求的重要部分。 它们是...
SELECT
语句只针对CTE进行选择,不选择其他内容(没有连接等),并且SELECT
语句只指定一个 WHERE
子句。这纯粹是一个过滤语句。简而言之,答案是否定的。唯一的方法是 保证 订购时要有 ORDER BY
子句,但在这种情况下,不需要在CTE中对结果进行排序。但是在这种情况下,不需要在CTE中对结果进行排序。
然而,如果排序表达式很复杂,而且你 需要 在派生CTE中进行排序(例如,由于使用了 OFFSET/FETCH
或 ROWNUM
),您可以根据原始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
不,结果并不能保证和子查询的顺序一样。从来没有,也不会有。你可能会观察到某种行为,特别是当CTE被具体化的时候,你可以尝试用优化器提示来影响这种行为,比如说 /*+ MATERIALIZE */
和 /*+ INLINE */
. 然而,查询优化器的行为还取决于数据量、IO v cpu速度,最重要的是取决于数据库版本。例如,Oracle 12.2引入了一个名为 "内存中游标持续时间Temp表 "的功能,它试图加快像你这样的查询,而不保留子查询中的顺序。
我赞同@Nick的建议,在子查询中增加一个行号字段。