2012-12-27 85 views
1

我正在尋找一種方法來查找範圍內的缺失數字。我在同一個表中有一個開始數字列和一個結束數字列。如何找到2列之間的缺失數字?

我想要跳過的數字。我可以得到下一個跳過的號碼,但不知道如何獲得不在範圍內的號碼列表。我有一個數字表,如果這將是有用的。

這是我的例子:

doc_num_begin doc_num_end 
------------- ----------- 
20000007  20000008 
20000011  20000015 
20000016  20000017 

我想獲得20000009,20000010。我已經搜索,但無法找到如何使用開始和結束列來做到這一點。

感謝

+0

可以錯過多少個大號數字範圍? –

+0

用戶可以提供20000007-20000100這樣的範圍。 –

回答

4

如果你有一個數字表,那麼這是很容易的:

select n.num 
from Numbers n left outer join 
    RangeTable rt 
    on n.number between rt.doc_num_begin and doc_num_end 
where rt.doc_num_begin is null 

這是做一個左外從號碼加入到範圍表,然後保持那些不匹配。

雖然表達起來很容易,但由於非等距連接,性能可能會相當差。你可能還想在數字表中加入條件,所以你不要從0,1開始。 。中,當在範圍內啓動20000007.你會做,因爲:

select n.num 
from Numbers n join 
    (select MIN(doc_num_begin) as MinVal, MAX(doc_num_end) as MaxVal from RangeTable) const 
    on n.number between const.MinVal and const.MaxVal left outer join 
    RangeTable rt 
    on n.number between rt.doc_num_begin and doc_num_end 
where rt.doc_num_begin is null 
+0

謝謝戈登。我試過了,看起來不錯。 –

+0

表中的範圍可能從一個相當大的點開始,不在數字表中。但是,通過在第二個查詢中更改連接條件,可以很容易地解決這個問題:'on n.number between 0 and const.MaxVal - const.MinVal',第二個條件'on n.number between rt .doc_num_begin - const.MinVal和rt.doc_num_end - const.MinVal'。當然,這仍然需要const.MinVal和const.MaxVal之間的差異不超過數字表中的最大數量。 –

0

可以使用已知序列號中的任何表或示例數據庫用於此目的,這個ID來進行篩選。 交叉加入此ID,將延長您尋求的限制。

SELECT i from (select (w2.WorkOrderID-1)+(w1.WorkOrderID-1)*10000 as i 
from AdventureWorks.Production.WorkOrder w1 
cross join AdventureWorks.Production.WorkOrder w2 
where w1.WorkOrderID<10000 and w2.WorkOrderID<10000) as MyNumbers 
WHERE i BETWEEN @StartRange and @EndRange 
and not exists (SELECT 1 FROM MyTable 
WHERE i BETWEEN doc_num_begin doc_num_end) 
1

如果你只需要找到丟失的範圍,你可以使用此查詢:

SELECT 
    t1.doc_num_end + 1 as start_missing_range, 
    MIN(t2.doc_num_begin) - 1 as end_missing_range 
FROM 
    your_table t1 INNER JOIN your_table t2 
    ON t1.doc_num_end < t2.doc_num_begin 
GROUP BY 
    t1.doc_num_end 
HAVING 
    MIN(t2.doc_num_begin) - t1.doc_num_end > 1 

編輯:而這種查詢可以用於擴展範圍:

SELECT num+start_missing_range 
FROM 
    (select 0 as num 
    union all select 1 as num 
    union all select 2 as num 
    union all select 3 as num 
    union all select 4 as num 
    union all select 5 as num 
    union all select 6 as num 
    union all select 7 as num 
    union all select 8 as num 
    union all select 9 as num) numbers inner join 
    (SELECT 
    t1.doc_num_end + 1 as start_missing_range, 
    MIN(t2.doc_num_begin) - 1 as end_missing_range 
    FROM 
    your_table t1 INNER JOIN your_table t2 
     ON t1.doc_num_end < t2.doc_num_begin 
    GROUP BY 
    t1.doc_num_end 
    HAVING 
    MIN(t2.doc_num_begin) - t1.doc_num_end > 1) rg 
    on end_missing_range-start_missing_range>=numbers.num 

(只有當一個範圍包含最多10個數字時,它才能工作,它可以很容易地擴展到更多...當然,總會有一個限制,但至少你不需要d表中所有數字)

+0

這可以進一步擴展到使用數字表來「展開」範圍。 –

+0

@AndriyM我擴大我的答案一點,展開範圍(限制爲10個數字) – fthiella

+0

我同意你可以沒有永久性數字表。儘管如此,一個數字表可以有很多用途,所以堅持一組數字可能是合理的。即使它只是一個,但經常被稱爲需要它的查詢,你仍然會發現使用一個*索引的*數字表格是有好處的。無論如何,即使在你更新之前,你的方法對我來說似乎值得讚不絕口,所以,工作很好! :) –

相關問題