我可以使用SQL在下面给出的示例表中找到缺少的数字吗?

时间:2009-05-22 19:07:29

标签: sql sql-server database algorithm

假设我的下表有三列:

id | start_block | end_block
-----------------------------
01 | 00000000001 | 00000000005
02 | 00000000006 | 00000000011
03 | 00000000012 | 00000000018
04 | 00000000025 | 00000000031
05 | 00000000032 | 00000000043

每行是“开始块”和“结束块”。如果数据是完美的,那么每个起始块将比它之前的结束块多一个。因此,对于行id == 02,起始块为6,而前一行的结束块为5。

我需要查询这些数据(它是成千上万行)并查找丢失的行。根据我的示例数据,03和04之间应该有一行,其起始块为19,结束块为24。

我正在尝试在JSP中构建一个报告来协调这些数据并找到丢失的行。执行此操作的丑陋方法是将整个记录集拉入数组并执行类似于每一行的操作:

if ((arry(i,1) + 1) != (arry(i+1),1)( {
  print("Bad Row!\n");
}

但是,我真的希望能够直接查询记录集并返回我需要的内容。那可能吗?如果没有,有人会指出我正确的方向创建一个存储过程,做我需要的吗?

8 个答案:

答案 0 :(得分:10)

尝试一下肯定不会受伤

CREATE TABLE #t (startz INT, zend INT)
insert into #t (startz, zend) values (1,5)
insert into #t (startz, zend) values (6,11)
insert into #t (startz, zend) values (12,18)
insert into #t (startz, zend) values (25,31)
insert into #t (startz, zend) values (32,43)

select * from #t ta
LEFT OUTER JOIN #t tb ON tb.startz - 1 = ta.zend
WHERE tb.startz IS NULL

最后的结果是假阳性。但很容易消除。

答案 1 :(得分:2)

你可以尝试:

SELECT t.ID, t.Start_Block, t.End_Block
FROM [TableName] t
JOIN [TableName] t2 ON t.ID = t2.ID+1
WHERE t.Start_Block - t2.End_Block > 1

答案 2 :(得分:1)

这样做。您可能还想查找重叠块。

SELECT
     T1.end_block + 1 AS start_block,
     T2.start_block - 1 AS end_block
FROM
     dbo.My_Table T1
INNER JOIN dbo.My_Table T2 ON
     T2.start_block > T1.end_block
LEFT OUTER JOIN dbo.My_Table T3 ON
     T3.start_block > T1.end_block AND
     T3.start_block < T2.start_block
WHERE
     T3.id IS NULL AND
     T2.start_block <> T1.end_block + 1

答案 3 :(得分:0)

 Select * From Table O
   Where 
      (Exists
         (Select * From Table
          Where End_Block < O.Start_Block)
       And Not Exists 
         (Select * From Table
          Where End_Block = O.Start_Block - 1)) 
    Or
      (Exists
         (Select * From Table
          Where Start_Block > O.End_Block)
       And Not Exists 
         (Select * From Table
          Where Start_Block = O.End_Block + 1 )) 

答案 4 :(得分:0)

select e1.end_block + 1 as start_hole,
    (select min(start_block) 
     from extent e3 
     where e3.start_block > e1.end_block) - 1 as end_hole
from extent e1 
left join extent e2 on e2.start_block = e1.end_block + 1
where e2.start_block is null 
and e1.end_block <> (select max(end_block) from extent);

虽然我认为这是在TSQL中迭代结果的合理候选者:你将不得不扫描整个表(或至少start_block和{{1的整个索引无论如何,所以只循环一次并使用变量来记住最后一个值是目标。

答案 5 :(得分:0)

这是一个实际上告诉你缺少行的SQL!

它是否非常快,因此忽略性能问题:

基于:

CREATE TABLE #t (startz INT, zend INT)
insert into #t (startz, zend) values (1,5)
insert into #t (startz, zend) values (6,11)
insert into #t (startz, zend) values (12,18)
insert into #t (startz, zend) values (25,31)
insert into #t (startz, zend) values (32,43)
insert into #t (startz, zend) values (45,58)
insert into #t (startz, zend) values (60,64)
insert into #t (startz, zend) values (70,98)


select tab1.zend+1 as MissingStartValue,
       (select min(startz-1) from #t where startz > tab1.zend+1) as MissingEndValue
 from #t as tab1 where not exists (select 1 from #t as tab2 where tab1.zend + 1 = tab2.startz)
and (select min(startz-1) from #t where startz > tab1.zend+1) is not null 

答案 6 :(得分:0)

select * from blocks a
where not exists (select * from blocks b where b.start_block = a.end_block + 1)

会在间隙前面给出块。你可以得到幻想。我们看看......

select a.end_block, min(b.start_block)
from blocks a,
     blocks b
where not exists (select * from blocks c where c.start_block = a.end_block + 1)
and b.start_block > a.end_block
group by a.end_block

我认为应该这样做。

答案 7 :(得分:0)

SELECT t1.End_Block + 1 as Start_Block,
       t2.Start_Block - 1 as End_Block,
  FROM Table as t1, Table as t2
 WHERE t1.ID + 1 = t2.ID
   AND t1.End_Block + 1 <> T2.Start_Block 

这假定表中的ID是顺序的。如果它们不是顺序的,那么你必须使用Start_Block到End_Block进行一些复杂的链接,以链接彼此相邻的两个块。