如何解决如何选择两个数字之间未占用的范围
考虑我有下表:
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 举报,一经查实,本站将立刻删除。