当多次引用CTE时,SQL row_number顺序是否有保证?

时间:2016-05-06 09:53:51

标签: sql common-table-expression window-functions

如果我的CTE定义使用了由非唯一列排序的row_number(),并且我在查询中引用了两次CTE,那么对于两个引用,每行的row_number()值保证相同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的值?

http://rextester.com/AQDXP74920

上的示例查询

我怀疑在任何一种情况下都无法保证。如果没有这样的保证,那么如果在查询中可能多次引用CTE,则所有使用row_number()的CTE应始终按唯一的列组合排序。

我以前从未听过这个建议,并且想要一些专家意见。

2 个答案:

答案 0 :(得分:3)

不,无法保证非唯一排序列表中的ROW_NUMBER在多次引用CTE时返回相同的序列。它很可能会发生,但不会保证,因为CTE仅仅是一种观点。

因此,总是在这种情况下使排序列表唯一,例如order by name, id

答案 1 :(得分:3)

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

SQL Server的用户经常将CTE视为"临时表"或"派生表。但是,它们并不是那种。虽然有些数据库确实实现了CTE(至少在某些时候),但SQL Server从未实现CTE。

实际上,会发生的事情是CTE逻辑插入到查询中 - 就像"替换(,)"用于查询。这会影响非唯一排序键。它还会影响一些非确定性函数,例如NEWID()

您的案例中的建议很简单:每当您使用order by时,请使用唯一键作为最后一个order by键。无论是在窗口函数中还是在查询中使用order by,都应该这样做。这是一个习惯的安全习惯。