【问题标题】:SQL Server - Building out a dynamic range of numbers while grouping by a specific columnSQL Server - 在按特定列分组时构建动态数字范围
【发布时间】:2018-12-25 18:43:29
【问题描述】:

我有以下数据:

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】:

    您可以使用递归 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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-12-18
      • 1970-01-01
      • 2020-09-08
      • 2014-05-17
      • 1970-01-01
      • 2018-12-15
      • 1970-01-01
      相关资源
      最近更新 更多