2009-05-22 2 views
4

Disons que je le tableau suivant avec trois colonnes:Puis-je utiliser SQL pour trouver les numéros manquants dans l'exemple de tableau ci-dessous?

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

Chaque ligne était un « Start Block » et un « End Block ». Si les données étaient parfaites, chaque bloc de départ serait un de plus que le bloc de fin précédent. Donc, pour id de rangée == 02, le bloc de départ est 6 tandis que le bloc de fin pour la ligne avant lui 5.

J'ai besoin d'interroger ces données (il s'agit de dizaines de milliers de lignes) et trouver toutes les lignes manquantes. Selon mes données d'exemple, il devrait y avoir une ligne entre 03 et 04 qui a un bloc de départ de 19 et un bloc de fin de 24.

J'essaye de construire un rapport dans JSP pour réconcilier ces données et trouver les lignes manquantes. La façon laide de le faire serait de tirer l'ensemble d'enregistrements dans un tableau et faire quelque chose comme sur chaque ligne:

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

Mais, je voudrais vraiment pouvoir interroger directement le jeu d'enregistrements et retourner ce que je dois . Est-ce possible? Si non, quelqu'un pourrait-il me diriger dans la bonne direction pour créer un proc stocké qui fait ce dont j'ai besoin?

+0

Je suppose que je devrais mentionner que j'utilise Microsoft SQL Server 2005. – messick

+0

Que sont les types de données de colonne? –

+0

id est int, les deux autres sont des chaînes. – messick

Répondre

10

Bien sûr, ne serait pas de mal à essayer

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 

Le dernier résultat est un faux positif. Mais facile à éliminer.

+0

Vous suggérez qu'il écrive ceci pour "des dizaines de milliers de rangées"? – DOK

+2

3 lignes pour des dizaines de milliers de lignes? Pourquoi pas? Ceci est un exemple, l'auteur du problème trouvera son propre moyen d'importer ses données. – hova

+0

D'accord, seulement 3 lignes. Je ne suis pas sûr pourquoi vous auriez à écrire ceci plus d'une fois pour "des dizaines de milliers de rangées". –

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)) 
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); 

Bien que je dirais que c'est un candidat raisonnable pour itérer le résultat dans TSQL: vous allez devoir balayer toute la table (ou au moins l'ensemble des indices sur start_block et end_block) de toute façon Donc, boucler juste une fois et en utilisant des variables pour se souvenir de la dernière valeur est quelque chose à viser.

2

Vous pouvez essayer:

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

+1 réponse de poing de ce type et cela fonctionnera rapidement si les ID sont consécutifs – Andomar

1

Cela fera. Vous pouvez également rechercher des blocs qui se chevauchent.

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

Voici un SQL qui vous indique les lignes manquantes!

assez rapide est-elle apparue donc ignorer les problèmes de performance:

Basé sur:

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

Vous suggérez qu'il écrit cela pour "des dizaines de milliers de lignes"? – DOK

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

vous donnerait les blocs précédant immédiatement un écart. Vous pourriez avoir envie. Voyons voir ...

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 

Je pense que cela devrait le faire.

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 

Cela suppose que les ID de la table sont séquentiels. Si elles ne sont pas séquentielles, vous devez effectuer une liaison compliquée avec Start_Block à End_Block pour lier les deux blocs adjacents.

Questions connexes