Могу ли я использовать SQL для поиска пропущенных чисел в приведенной ниже таблице примеров? - PullRequest
4 голосов
/ 22 мая 2009

Допустим, у меня есть следующая таблица с тремя столбцами:

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

Каждая строка представляла собой «Начальный блок» и «Конечный блок». Если бы данные были безупречны, каждый начальный блок был бы на один больше, чем конечный блок перед ним. Таким образом, для идентификатора строки == 02 начальный блок равен 6, а конечный блок для строки перед ним - 5.

Мне нужно запросить эти данные (это десятки тысяч строк) и найти пропущенные строки. Согласно моим образцам данных, между 03 и 04 должна быть строка с начальным блоком 19 и конечным блоком 24.

Я пытаюсь создать отчет в JSP, чтобы согласовать эти данные и найти пропущенные строки. Уродливый способ сделать это - вытащить весь набор записей в массив и сделать что-то вроде каждой строки:

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

Но мне бы очень хотелось иметь возможность напрямую запрашивать набор записей и возвращать то, что мне нужно. Это возможно? Если нет, может кто-нибудь указать мне правильное направление создания хранимого процесса, который делает то, что мне нужно?

Ответы [ 8 ]

10 голосов
/ 22 мая 2009

Конечно, не мешало бы попробовать

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

Последний результат - ложное срабатывание. Но легко устранить.

2 голосов
/ 22 мая 2009

Вы можете попробовать:

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
1 голос
/ 22 мая 2009

Это сделает это. Вы также можете искать перекрывающиеся блоки.

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
0 голосов
/ 23 мая 2009
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 

Предполагается, что идентификаторы в таблице являются последовательными. Если они не последовательные, вам нужно выполнить сложное связывание Start_Block с End_Block, чтобы связать два блока, смежные друг с другом.

0 голосов
/ 23 мая 2009
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

Я думаю, это должно быть сделано.

0 голосов
/ 22 мая 2009

Вот 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 
0 голосов
/ 22 мая 2009
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 и end_block) так что циклический просмотр всего один раз и использование переменных для запоминания последнего значения - это то, к чему нужно стремиться.

0 голосов
/ 22 мая 2009
 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 )) 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...