ROW_NUMBER 在 CTE 中不起作用

ROW_NUMBER is not working in CTE

我正在研究报告,似乎 row_number 在递归中不起作用。

!!我已经简化了示例!

来自 table,有 3 条记录:

declare @sometable table (id int, id2 int)
insert into @sometable
select 1 as id,   11 as id2   
union all
select 2,         22   
union all
select 3,        33    

在 CTE 中 select 全部并标记要在下一次迭代中排除的第一条记录:

;with cte(iteration, ord, id, id2, deal) as 
(
select ordered.*
    , deal = (case when ord = 1 then 1 else 0 end)
from 
    (select 1 iteration,
        ord = ROW_NUMBER() OVER (ORDER BY id),
        st.*
    FROM @sometable st) ordered

)
select * from CTE
union all
    select 
    ordersinverted.nextIteration,
    ordersinverted.ord,
    ordersinverted.id,              
    ordersinverted.id2,
    deal = (case when ord = 1 then 1 else 0 end)
from (
    select 
        ROW_NUMBER() OVER (PARTITION BY ord ORDER BY iteration desc) as reversedIteration,
        ROW_NUMBER() OVER (ORDER BY cte.id) as ord,
        iteration + 1 as nextIteration,                 
        cte.id, 
        cte.id2                 
    from cte 
    where cte.deal = 0
) ordersinverted

它给了我 3 次迭代的预期结果: 使用 row_number out of CTE result

我非常希望得到类似的结果并递归调用select。不幸的是,这是怀疑存在错误的地方:

;with cte(iteration, ord, id, id2, deal) as 
(
    select ordered.*
        , deal = (case when ord = 1 then 1 else 0 end)
    from 
        (select 1 iteration,
            ord = ROW_NUMBER() OVER (ORDER BY id),
            st.*
        FROM @sometable st) ordered
union all
    select 
        ordersinverted.nextIteration,
        ordersinverted.ord,
        ordersinverted.id,              
        ordersinverted.id2,
        deal = (case when ord = 1 then 1 else 0 end)
    from (
        select 
            ROW_NUMBER() OVER (PARTITION BY ord ORDER BY iteration desc) as     reversedIteration,
            ROW_NUMBER() OVER (ORDER BY cte.id) as ord,
            iteration + 1 as nextIteration,                 
            cte.id, 
            cte.id2                 
        from cte 
        where cte.deal = 0
    ) ordersinverted
)
select * from CTE

使用row_numberwithin CTE result

哦,对不起。这必须有一个问题格式: 所以我的问题是:这是功能还是错误?

请注意,对 Oracle 的类似查询将按预期工作:

with T (id,grp_id) as (
select 1 as id,1 as grp_id from dual union all
select 2 as id,1 as grp_id from dual union all
select 3 as id,1 as grp_id from dual union all
select 1 as id,2 as grp_id from dual union all
select 2 as id,2 as grp_id from dual union all
select 3 as id,2 as grp_id from dual )
,
rec (id,grp_id,rn) as (
 select id, grp_id, row_number()over(partition by grp_id order by id) rn from T where grp_id=1 
 union all
 select t.id, t.grp_id, row_number() over(partition by t.grp_id  order by t.id) rn from T inner join rec on t.id=rec.id and t.grp_id=rec.grp_id+1

)

PS。如果使用 max() 或 min() 函数,它的工作方式类似...

这是记录在案的行为。因此,它应该被视为 "feature"。这是此案例的文档:https://msdn.microsoft.com/en-us/library/ms175972.aspx

Analytic and aggregate functions in the recursive part of the CTE are applied to the set for the current recursion level and not to the set for the CTE. Functions like ROW_NUMBER operate only on the subset of data passed to them by the current recursion level and not the entire set of data passed to the recursive part of the CTE. For more information, see example K. Using analytical functions in a recursive CTE that follows.

本文的第 K 段有一个很好的演示,演示了 ROW_NUMBER 函数在递归 CTE 中的行为。因为递归CTE是逐行处理数据,所以CTE递归部分的ROW_NUMBER永远是return 1,可以把ROW_NUMBER() OVER (ORDER BY id)改成COUNT(*) OVER (),看看有多少行 SQL 服务器进程同时用于锚点和 CTE 的递归部分。分别会有3个和1个