一个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 函数还是用于查询,您都应该这样做。习惯了才是安全的习惯。
如果我的 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 函数还是用于查询,您都应该这样做。习惯了才是安全的习惯。