【问题标题】:Create list of numbers from list of ranges从范围列表创建数字列表
【发布时间】:2015-06-02 16:20:29
【问题描述】:

我有一个包含两列的表,其中包含整数序列的开头和结尾。这是一个很大的列表,但我很确定在任何范围内都没有重叠。我想生成一个包含在这些范围开始和结束范围内的所有数字的列表。

基本上我想做这个问题的反面:How to create number ranges from a list of numbers?

根据我的阅读,我对解决方案的最佳猜测可能是某种动态交叉应用,但我什至不确定如何开始。

我的桌子看起来像这样:

表格

RangeStart RangeEnd
200        205
208        209
221        221
222        224

我想要这样的东西:

期望的结果

Sequence
200
201
202
203
204
205
208
209
221
222
223
224

【问题讨论】:

  • 你想使用 sql 是因为?
  • @Strawberry 如果你唯一的工具是锤子......

标签: sql sql-server


【解决方案1】:

您可以通过使用递归公用表表达式来避免使用“数字”表:

WITH Numbers AS (
SELECT RangeStart, RangeStart AS Number, RangeEnd from RangeTable
UNION ALL
SELECT RangeStart, Number + 1, RangeEnd FROM Numbers WHERE Number < RangeEnd)
SELECT Number FROM Numbers ORDER BY Number

第一部分是'anchor'查询,它定义了根成员(在这种情况下,范围从数字、范围中的第一个数字和范围到数字)。

第二部分(在UNION ALL 之后)递归地加入到锚成员并基本上不断地向Number 添加一个并递归直到它到达RangeEnd

最后一部分仅从我们构建的 CTE 中获取数字(我们不再对范围开始和结束感兴趣)并确保它们的顺序正确(这对您来说可能无关紧要,在这种情况下您可以省略ORDER BY 子句。)

编辑 - 如果您遇到递归限制,您可以通过在查询末尾添加 OPTION (MAXRECURSION 0) 来解决此问题。很抱歉错过了这个!

【讨论】:

  • 我喜欢这个,但你可能会遇到最大递归问题...Msg 530, Level 16, State 1, Line 13 The statement terminated. The maximum recursion 100 has been exhausted before statement completion.
  • 我可能会补充一点,使用 CTE 以这种方式生成数字范围有几个优点,其中最重要的是它不依赖于任何“数字表”的存在(或可访问性) '。这里对生成范围的各种方法进行了很好的讨论:stackoverflow.com/questions/1393951/…
  • @CrappyCodingGuy - 您可以通过在查询末尾添加提示 OPTION (MAXRECURSION 0) 轻松绕过最大递归限制
  • 感谢@EdB。我需要最大递归的修复
  • 是的,但是最大递归是有原因的。如果您的范围不大,那么这可能不是问题。
【解决方案2】:

最简单的方法是从整数列表开始。一个方便的——如果列表不太长的话——是master..spt_values

with n as (
      select row_number() over (order by (select null)) - 1 as n
      from master..spt_values
     )
select (rangestart + n.n) as sequence
from ranges r join
     n
     on r.rangestart + n.n <= r.rangeend
order by sequence;

如果您担心重叠,那么以下是获取序列的简单方法:

select distinct (rangestart + n.n) as sequence
from ranges r join
     n
     on r.rangestart + n.n <= r.rangeend
order by sequence;

如果问题有很多重叠和价值,那么你会想要一种稍微不同的方法(但这不是你要问的问题)。

【讨论】:

    【解决方案3】:
    declare @Sequence table(
      Value int
    )
    
    declare @Value int = 0
    
    while (@Value < 500)
      begin
        insert @Sequence values(@Value)
        select @Value += 1
      end
    
    select * from @Sequence
    
    declare @Ranges table(
      RangeStart int,
      RangeEnd int
    )
    
    insert into @Ranges values(200, 205)
    insert into @Ranges values(208, 209)
    insert into @Ranges values(221, 221)
    insert into @Ranges values(222, 224)
    
    
    select s.Value
    from @Sequence s
    join @Ranges r on r.RangeStart <= s.Value and r.RangeEnd >= s.Value
    order by s.Value
    

    关键是获取您的@Sequence 值列表。

    【讨论】:

      猜你喜欢
      • 2010-11-27
      • 1970-01-01
      • 2020-03-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多