微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何选择两个数字之间未占用的范围

如何解决如何选择两个数字之间未占用的范围

考虑我有下表:

Id   | Title        | Start   | End    
-----+--------------+---------+-----
1    | Group A      | 100     | 200
-----+--------------+---------+-----
2    | Group B      | 350     | 500
-----+--------------+---------+-----
3    | Group C      | 600     | 800

我想获得 100 到 999 之间的未占用范围。 我要求的最终结果是:

Id   |  Start   | End    
-----+----------+-----
1    | 201      | 349
-----+----------+-----
2    | 501      | 599
-----+----------+-----
3    | 801      | 999

解决方法

你可以使用lead()窗口函数来做到这一点。

Select Id,[End]+1 as Start,coalesce((lead(start)over(order by id) -1),999) [End] 
from mytable

由于 Lead() 的最后一行结果将为 null,因此我使用了 coalesce() 使其为 999。

架构:

 create table mytable( Id   int,Title varchar(50),[Start] int,[End]    int);
 insert into mytable values(1,'Group A',100,200);
 insert into mytable values(2,'Group B',350,500);
 insert into mytable values(3,'Group C',600,800);

查询:

 Select Id,[End]+1 as [Start],coalesce((lead([start])over(order by id) -1),999) [End] 
 from mytable

输出:

Id 开始 结束
1 201 349
2 501 599
3 801 999

dbfiddle here

,

这是一个棘手的问题。如果我做出以下假设:

  • 所有值都在 100 到 999 之间。
  • 这些值没有重叠。

然后你可以用 lead()union all 处理这个:

select null,min(starti) - 1
from t
having min(starti) > 100
union all
select title,endi + 1,next_starti - 1
from (select lead(starti,1,1000) over (order by starti) as next_starti,t.*
      from t
     ) t
where next_starti >= endi + 1;

请注意,第一个子查询针对的不是示例数据中的条件,而是第一个值在 100 之后开始的条件。

对于可能有重叠的更通用的解决方案,最简单的方法可能是概括所有可能的值,删除存在的值,然后组合相邻的值:

with n as (
     select 100 as n
     union all
     select n + 1
     from n
     where n < 999
    )
select min(n),max(n)
from (select n.*,row_number() over (order by n) as seqnum
      from n 
      where not exists (select 1 from t where n.n between t.starti and t.endi)
     ) tn
group by (n - seqnum)
order by min(n)
option (maxrecursion 0);

Here 是一个 dbfiddle。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。