带递归的CTE - row_number()聚合

Ed *_*d W 10 sql t-sql sql-server recursion

我有一个父/子关系表和一个引用自己的日期创建列.我想显示每个父记录以及节点上最近的"活动"所排序的所有后代.因此,如果很久以前创建的第1行有一个新的子项添加到其中(或者例如将一个新子项添加到其子项中),那么我希望它位于结果的顶部.

我目前无法正常工作.

我的表结构如下:

CREATE TABLE [dbo].[Orders](
    [OrderId] [int] NOT NULL,
    [Orders_OrderId] [int] NULL,
    [DateOrdered] datetime)
Run Code Online (Sandbox Code Playgroud)

我编写了以下SQL来提取信息:

WITH allOrders AS 
   (SELECT po.orderid, po.Orders_OrderId, po.DateOrdered, 0 as distance,  
   row_number() over (order by DateOrdered desc) as RN1
    FROM orders po WHERE po.Orders_OrderId is null
    UNION ALL
    SELECT b2.orderid ,b2.Orders_OrderId, b2.DateOrdered, c.distance + 1, 
    c.RN1
    FROM orders b2 
    INNER JOIN allOrders c 
    ON b2.Orders_OrderId = c.orderid
    )

SELECT * from allOrders
where RN1 between 0 and 2
order by rn1 asc, distance asc
Run Code Online (Sandbox Code Playgroud)

有什么方法可以"聚合"递归选择的结果,这样我就可以选择整个"父"节点的最大日期?

SQLFiddle演示:http://sqlfiddle.com/#!3/ca6cb/11 (记录号1应该是第一个,因为它有一个最近更新的子)

更新 感谢@twrowsell的建议我有以下查询,它确实有效,但看起来非常笨重,并且有一些性能问题,我觉得我不应该有3个CTE来实现这一点.有没有什么方法可以在保留"行号"的同时进行压缩(因为这是用于分页的用户显示)?

WITH allOrders AS 
  (SELECT po.orderid, po.Orders_OrderId, 0 as distance, po.DateOrdered, po.orderid as [rootId]
    FROM orders po WHERE po.Orders_OrderId is null 
    UNION ALL
    SELECT b2.orderid ,b2.Orders_OrderId, c.distance + 1, b2.DateOrdered, c.[rootId]
    FROM orders b2     
    INNER JOIN allOrders c 
    ON b2.Orders_OrderId = c.orderid
    ),
    mostRecentOrders as (
    SELECT *,
    MAX(DateOrdered) OVER (PARTITION BY rootId) as [HighestOrderId]
    from allOrders
    ),
    pagedOrders as (
    select *, dense_rank() over (order by [HighestOrderId] desc) as [PagedRowNumber] from mostRecentOrders)

    SELECT  * from pagedOrders
    where PagedRowNumber between 0 and 2
    order by [HighestOrderId] desc
Run Code Online (Sandbox Code Playgroud)

此外,我可以使用MAX(orderid)orderid作为ident和datecreated创建后我的方案中无法更新.

更新了SQLFiddle:http://sqlfiddle.com/#!3/ca6cb/41

twr*_*ell 1

将在外部选择工作的 OVER 子句中对 DateOrdered 使用 MAX 吗?

    WITH allOrders AS 
(
    SELECT po.orderid, po.Orders_OrderId, po.DateOrdered, 0 as distance,  
       row_number() over (order by DateOrdered desc) as RN1
    FROM orders po WHERE po.Orders_OrderId is null
    UNION ALL
    SELECT b2.orderid ,b2.Orders_OrderId, b2.DateOrdered, c.distance + 1, 
      c.RN1
    FROM orders b2 
    INNER JOIN allOrders c 
    ON b2.Orders_OrderId = c.orderid
    )


    SELECT *,   MAX(DateOrdered) OVER (PARTITION BY Orders_OrderId) from allOrders
    where RN1 between 0 and 2
    order by rn1 asc, distance asc
Run Code Online (Sandbox Code Playgroud)

编辑: 抱歉,我第一次误解了您的要求。看起来您想按 RN1 字段而不是 Orders_OrderId 对结果进行分区,因此您的外部选择将类似于..

 SELECT MAX(DateOrdered) OVER (PARTITION BY RN1 ),*  from allOrders
where RN1 between 0 and 2
order by rn1 asc, distance asc
Run Code Online (Sandbox Code Playgroud)