一个CTE被多次引用,能保证SQLrow_number顺序吗?

Is SQL row_number order guaranteed when a CTE is referenced many times?

如果我的 CTE 定义使用按非唯一列排序的 row_number(),并且我在查询中两次引用该 CTE,则每个的 row_number() 值是行 gua运行对于 CTE 的两个引用是否相同?

示例 1:

with tab as (
    select 1 as id, 'john' as name
    union 
    select 2, 'john'
    union 
    select 3, 'brian'
),
ordered1 as (
    select ROW_NUMBER() over (order by name) as rown, id, name
    from tab
)
select o1.rown, o1.id, o1.name, o1.id - o2.id as id_diff
from ordered1 o1
join ordered1 o2 on o2.rown = o1.rown

输出:

+------+----+-------+---------+
| rown | id | name  | id_diff |
+------+----+-------+---------+
|    1 |  3 | brian |       0 |
|    2 |  1 | john  |       0 |
|    3 |  2 | john  |       0 |
+------+----+-------+---------+

是否保证运行所有行都id_diff = 0

示例 2:

with tab as (
    select 1 as id, 'john' as name
    union 
    select 2, 'john'
    union 
    select 3, 'brian'
),
ordered1 as (
    select ROW_NUMBER() over (order by name) as rown, id, name
    from tab
),
ordered2 as (
    select ROW_NUMBER() over (order by name) as rown, id, name
    from tab
)
select o1.rown, o1.id, o1.name, o1.id - o2.id as id_diff
from ordered1 o1
join ordered2 o2 on o2.rown = o1.rown

当我 运行 它时输出与上面相同,但这并不能证明什么。

现在我正在连接两个查询 ordered1 和 ordered2,是否可以对结果中 id_diff = 0 的值进行任何 gua运行tee ?

http://rextester.com/AQDXP74920

上的示例查询

我怀疑这两种情况都没有gua运行tee。如果没有这样的 gua运行tee,那么所有使用 row_number() 的 CTE 应该总是按唯一的列组合排序,如果 CTE 在查询中可能被多次引用。

我以前从未听过这个建议,想听听专家的意见。

不,当 CTE 被多次引用时,无法保证 ROW_NUMBER 在非唯一排序列表上 returns 相同的序列。这很可能会发生,但不能保证,因为 CTE 只是一种观点。

因此,在这种情况下,请务必使排序列表唯一,例如order by name, id.

Thorsten 的回答是正确的,我只是想补充一些细节。

SQL 服务器的用户经常将 CTE 视为 "temporary tables" 或“派生表”。然而,它们并非如此。尽管一些数据库确实实现了 CTE(至少在某些时候), SQL 服务器从未具体化 CTE。

事实上,CTE 逻辑被插入 到查询中——就像在查询中使用了"replace(, )" 一样。这会影响非唯一的排序键。它还会影响一些非确定性函数,例如 NEWID().

针对您的情况的建议很简单:无论何时使用 order by,都包含一个唯一键作为最后一个 order by 键。无论 order by 用于 window 函数还是用于查询,您都应该这样做。习惯了才是安全的习惯。