SQL Server - 在按特定列分组时构建动态范围的数字

问题描述 投票:0回答:1

我有以下数据:

ID                        Days
-----------------------   --------
1                         5
1                         10
1                         15

2                         5
2                         13
2                         15

我试图根据他们的ID进行分组,根据日期建立一系列数字。

对于ID组1:范围从5开始到9结束。下一个范围是10-14,然后最终范围是15-9999

对于ID组2:范围从5开始到12结束。下一个范围是13-14,然后最终范围是15-9999

结果表看起来像这样:

RangeStart  RangeEnd    RangeText   ID                                           
----------- ----------- ---------  ----
5           9           5 - 9         1                  
10          14          10 - 14       1     
15          9999        15 - 9999     1       
5           12          5 - 12        2                  
13          14          13 - 14       2     
15          9999        15 - 9999     2  

我试图使用CTE,但只有当我没有按ID分组时才有效。

Declare @RangeTable Table
(
ID Int,
RangeStart INT,
RangeEnd INT,
RangeText Varchar(50),
);with CTE as (
SELECT temp.Days,
rn = ROW_NUMBER() over(order by temp.Days asc),
temp.ID
FROM @TableWithDays temp)


INSERT @RangeTable
SELECT 
    ID= d1.ID,
    RangeStart= ISNULL(d1.Days, 0),
    RangeEnd  = ISNULL(d2.Days- 1, 9999),
    RangeText = 
    CASE WHEN (d1.Days = d2.Days - 1) 
    THEN CAST(d1.Days AS VARCHAR(100)) 
    ELSE
    ISNULL(CAST(d1.Days AS VARCHAR(100)),'0') + ISNULL(' - '+ 
    CAST(d2.Days - 1 AS VARCHAR(100)),' - 9999')END
FROM
CTE d1 LEFT JOIN
CTE d2 
   ON d1.rn = d2.rn - 1
sql sql-server sql-server-2008 stored-procedures
1个回答
1
投票

您可以使用递归CTE。这对lead()来说会更简单,但是没有。所以:

with t as (
      select t.*, t2.days as next_days
      from @TableWithDays t outer apply
           (select top (1) t2.*
            from @TableWithDays t2
            where t2.id = t.id and t2.days > t.days
            order by t2.days desc
           ) t2
     ),
     cte as (
      select t.id, t.days, t.next_days
      from t
      union all
      select cte.id, cte.days + 1, cte.next_days
      from cte
      where cte.days < cte.next_days or
            (cte.days < 9999 and cte.next_days is null)
     )
select *
from cte
with option (maxrecursion 0);
© www.soinside.com 2019 - 2024. All rights reserved.