如何在2列之间找到缺失的数字?

时间:2012-12-27 15:47:18

标签: sql sql-server-2005

我正在寻找一种方法来查找范围内的缺失数字。我在同一个表中有一个起始编号列和一个结束编号列。

我试图获取跳过的数字。我可以获得下一个跳过的数字,但不知道如何获得不在范围内的数字列表。我有一个数字表,如果这将是有用的。

以下是我的例子:

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

我想得到20000009,20000010。我已搜索但无法使用开始和结束列找到如何执行此操作。

由于

3 个答案:

答案 0 :(得分: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

答案 1 :(得分: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个数字时才会起作用,它可以很容易地扩展到更多......当然,总会有一个限制,但至少你不需要一个包含所有数据的表格数字)

答案 2 :(得分: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)