2012-11-30 31 views
6

簡化我的問題向下 - 我已經6位,其分配編號,以從1開始和結束到999999大多數數字客戶場順序分配,但數字可以由用戶手動分配,並且該特徵在整個範圍內以不可預測的模式使用。定義範圍,以覆蓋在多個序列間隙(T-SQL)

我們現在需要確定尚未分配(容易)號 - 然後轉換爲數字範圍內的這種(看似複雜)。

例如獲得以下幾號已分配

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中完成。

回答

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 

參考:由伊茨克奔淦

差距和島嶼高達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 
+0

連續最大stp_values.number是'2047'而它應該達到'999999'。 – GSerg

+0

@gserg您可以通過自我加入spt_values輕鬆創建更大數字的表格。 – podiluska

+0

我會簡單地在'spt_values'的無條件笛卡爾連接上使用'top(999999)'。 – GSerg

-1

創建一個號碼查詢,如果您有名爲「KH表「,例如列」myval「,這是您可以嘗試的整數列表是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 
+0

錯誤:「除非指定TOP或FOR XML,否則ORDER BY子句在視圖,內聯函數,派生表,子查詢和公用表表達式中無效。「 – MattH

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

+0

在你的CTE聲明之前你需要一個分號,否則你會得到一個語法錯誤:'關鍵字附近的語法錯誤',' – Bridge

+0

..或者頭部範圍 – podiluska

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 
+0

我更喜歡這種方法 - 但是如果第一個和最後一個數字未被使用,則不處理第一個和最後一個範圍 – MattH

1

這裏是SQLFiddle demo

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 
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 
+0

如果第一個條目丟失,則會錯過初始啓動範圍 – podiluska

+0

我嘗試過這種方法,並且在4分鐘後我的實際數據仍在運行除此之外,看起來不錯,謝謝。 – MattH