6

简化我的问题 - 我有 6 位字段,它为客户分配从 1 到 999999 的数字。大多数数字是按顺序分配的,但用户可以手动分配数字,并且此功能始终以不可预测的模式使用范围。

我们现在需要识别尚未分配的数字(简单) - 然后将其转换为多个范围(似乎很复杂)。

例如,给定以下数字已分配

1,2,3,4,5,
1001,1002,1003,1004,1005,
999101,999102,999103,999104,999105

我需要一组结果范围,例如

Start  End
6      1000
1006   999100
999106 999999

到目前为止,我的想法是这可能太复杂而无法在查询中编写 - 最好通过从 1 循环到 999999 并将范围添加到临时表来实现。

有兴趣听到我可以想象的想法,有几种方法。我正在使用 SQL Server 2008 R2。这是一次性练习,因此即使是非 SQL 解决方案也可能是合适的,例如,如果这在 Excel 中很容易完成。

4

6 回答 6

5

尝试这个

declare @t table (num int)

insert @t values (2),(3),(6),(7),(9),(10),(11)

select 
    MIN(number) as rangestart,
    MAX(number) as rangeend
from
(
    select *,
        ROW_NUMBER() over (order by number) -
        ROW_NUMBER() over (order by num,number) grp
    from 
    (   
        select number from master..spt_values where type='p' and number between 1 and 15 
    ) numbers 
    left join @t t
        on numbers.number = t.num       
) v
where num is null
group by grp

参考: itzik ben-gan 的间隙和岛屿

创建最多 999999 的数字查询

select p1.number +  p2.number * 2048 as number
from 
(select * from master..spt_values where type='p' ) p1,
(select * from master..spt_values where type='p' and number<489) p2    
where p1.number +  p2.number * 2048 <=999999
于 2012-11-30T10:01:01.470 回答
2
declare @t table (num int)

insert @t values 
(2),(3),(4),(5),
(1001),(1002),(1003),(1004),(1005),
(999101),(999102),(999103),(999104),(999105)

;with cte as
(
    select num,(ROW_NUMBER() OVER(ORDER BY num)) + 1 as idx from @t
    union
    select 0 [num],1 [idx] --start boundary
    union
    select 1000000 [num],COUNT(num) + 2 [idx] from @t --end boundary
)
select c1.num + 1 [Start], c2.num - 1 [End] 
from cte c1
inner join cte c2 on c2.idx = c1.idx + 1
where c2.num != c1.num + 1
于 2012-11-30T10:43:28.610 回答
1

这是SQLFiddle 演示

select 

case when max(n1)=0 then 1 else max(n1)end,
case when max(n2)=0 then 999999 else max(n2)end

from
(
select t.n+1 as n1,0 n2,
   row_number() over(order by t.n)
      +isnull((select 0 from t where n=1),1)  
      rn  
from t
left join t t2 on t.n+1=t2.n
where t2.n is null

union all 

select 0 n1, t.n-1 as n2 ,
row_number() over(order by t.n) rn 
from t
left join t t2 on t.n-1=t2.n
where t2.n is null
  and t.n>1
) t3
group by rn
于 2012-11-30T10:57:59.147 回答
1
create table #temp (id int)

insert into #temp (id)
values (1),(2),(3),(1000),(1001),(1002),(2000)

--drop table #temp
with cte as
(
select *, ROW_NUMBER() over(order by id) as rn
from #temp a 
)
select a.id + 1, b.id - 1
from cte a join cte b on a.rn = b.rn - 1 and a.id <> b.id -1

它不包括尾部范围,例如 2001-9999

于 2012-11-30T10:34:49.193 回答
1
declare @t table(id int)
insert @t values
(1),(2),(3),(4),(5),(1001),(1002),(1003),(1004),(1005),
(999101),(999102),(999103),(999104),(999105)

select t1.id+1 [start], coalesce(t3.[end], 999999) [end] 
from @t t1
left join @t t2 on t1.id +1 = t2.id
cross apply
(select min(id)-1 [end] from @t where t1.id < id
) t3
where t2.id is null
于 2012-11-30T11:18:35.933 回答
-1

if you have a table called "kh" for example with a column "myval" which is your list of integers you could try this SELECT.

SELECT MAX(t1.myval+1) AS 'StartRange',t3.myval-1 AS 'EndRange' 
FROM kh t1, kh t3
WHERE t1.myval+1 NOT IN (SELECT myval FROM kh t2 ORDER BY myval)
AND t3.myval-1 NOT IN (SELECT myval FROM kh t4 ORDER BY myval)
AND t1.myval < t3.myval
GROUP BY  t3.myval
ORDER BY StartRange
于 2012-11-30T10:32:26.677 回答