【问题标题】:ROW_NUMBER is not working in CTEROW_NUMBER 在 CTE 中不起作用
【发布时间】:2016-09-12 07:30:07
【问题描述】:

我正在研究报告,但似乎 row_number 不能以递归方式工作。

!!我已经简化了这个例子!!

来自有 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 中选择 All 并标记要在下一次迭代中排除的第一条记录:

;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_number within 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() 函数,它的工作原理类似......

【问题讨论】:

  • 我真的不知道您要实现/选择什么,但我怀疑,您的问题在于混合子查询、row_number 和递归 cte 以及 order sql服务器在其中执行查询。我认为您这样做会使查询不必要地复杂化。但是由于我真的不知道您实际上要做什么,因此根据输入,我无法更好地指定。与其尝试在单个查询中完成所有操作,不如将其拆分为更小的步骤。
  • 我想尝试的是 1)创建没有 row_number 的 CTE 2)创建 CTE2,它是 CTE 的 Select,其中包含 row_number。不知道你能不能试试
  • 感谢有关如何解决的建议。然而,这更能描述 MS SQL 中存在的问题。该脚本在 Oracle 中确实有效。将在此处添加示例一

标签: sql-server common-table-expression with-statement row-number


【解决方案1】:

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

CTE 递归部分中的分析和聚合函数是 应用于当前递归级别的集合而不是集合 对于 CTE。像 ROW_NUMBER 这样的函数只对 通过当前递归级别而不是全部传递给它们的数据 传递给 CTE 递归部分的数据集。更多 信息,请参见示例 K。在递归中使用分析函数 紧随其后的 CTE。

本文的第 K 段对递归 CTE 中 ROW_NUMBER 函数的行为进行了很好的演示。因为递归 CTE 逐行处理数据,所以 CTE 的递归部分中的 ROW_NUMBER 将始终返回 1。您可以将 ROW_NUMBER() OVER (ORDER BY id) 更改为 COUNT(*) OVER () 以检查 SQL Server 一次为锚点和CTE 的递归部分。分别有3个和1个。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    • 1970-01-01
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 2016-02-26
    相关资源
    最近更新 更多