2009-09-14 6 views
0

J'ai ce problème que je ne peux pas résoudre tout à fait. Je peux obtenir l'intervalle des nombres manquants, mais je ne peux pas les reconstituer à partir de ma série continue. Donc, si j'ai une série définie comme [1000,1001,1002,1003,1005,1006,1008], je veux extraire les trois séries continues [1000, 1001, 1002, 1003] et [1005, 1006] et [1008]. En utilisant un simple CTE, j'ai obtenu 1003, 1005, 1006 et 1008, donc je peux obtenir la fin et le début des intervalles, mais maintenant?Générer tous les intervalles continus d'une série

En fin de compte, je veux une table qui ressemble à ceci:

|to |from | 
|1000 |1003 | 
|1005 |1006 | 
|1008 |1008 | 

Quelqu'un at-il une solution intelligente qu'ils veulent partager?

EDIT: Voici le (probablement reduntant) CTE:

WITH MissingNumbers (FromNumber, ToNumber) AS 
( 
SELECT 
    T1.TaxLabelNumber, 
    T2.TaxLabelNumber 
FROM TaxLabel T1 
JOIN TaxLabel T2 
    ON T1.TaxLabelId + 1 = T2.TaxLabelId 
WHERE T1.TaxLabelNumber <> T2.TaxLabelNumber - 1 
) 
SELECT * INTO #TempNumbers 
FROM MissingNumbers 

EDIT2: Ofc. il y avait un changement de plans, donc je n'ai plus besoin de ce genre de solution. Merci pour toutes les réponses si! Très utile: D

Répondre

0

La solution la plus simple est d'avoir une table avec TaxLabelNumbers afin de pouvoir effectuer une jointure externe.

Il est également possible de créer ce type de table en CTE mais ce n'est pas très efficace.

with TaxLabelSeq(Number) as 
( 
    select @FromNumber as Number 
     union all 
    select Number + 1 
     from NumberSequence 
     where Number < @ToNumber 
) 

CTE avec sagesse par défaut 100 récurrences si vous avez besoin de manivelle que si vous avez besoin de plus de 100 numéros:

select * from TaxLabelSeq option (MaxRecursion 4711) 
0

Essayez cette

SELECT SSTART.num series_start, MIN(SEND.num) series_end 
FROM #series SSTART, #series SEND 
WHERE 
     /* anything that does not have a predecessor is a START */ 
     SSTART.num - 1 NOT IN (SELECT num FROM #series) AND 
     /* anything that does not have a following entry is an END */ 
     SEND.num + 1 NOT IN (SELECT num FROM #series) AND 
     /* now join each START with every END above it */ 
     SEND.num >= SSTART.num 
     /* we group over each START, so we can get the corresponding END with MIN */ 
GROUP BY SSTART.num 
0
WITH data AS 
     (
     SELECT 1000 AS number 
     UNION ALL 
     SELECT 1001 
     UNION ALL 
     SELECT 1002 
     UNION ALL 
     SELECT 1003 
     UNION ALL 
     SELECT 1005 
     UNION ALL 
     SELECT 1006 
     UNION ALL 
     SELECT 1008 
     ), 
     rows AS 
     (
     SELECT q2.number AS nnumber, q.number AS number 
     FROM (
       SELECT number 
       FROM data di 
       WHERE NOT EXISTS 
         (
         SELECT NULL 
         FROM data dn 
         WHERE dn.number = di.number - 1 
         ) 
       ) q 
       OUTER APPLY 
       (
       SELECT TOP 1 number 
       FROM data dp 
       WHERE dp.number < q.number 
       ORDER BY 
         dp.number DESC 
       ) q2 
     UNION ALL 
     SELECT TOP 1 number, NULL 
     FROM data 
     ORDER BY 
       number DESC 
     ), 
     rns AS 
     (
     SELECT *, ROW_NUMBER() OVER (ORDER BY nnumber) AS rn 
     FROM rows 
     ) 
SELECT re.number, rb.nnumber 
FROM rns re 
JOIN rns rb 
ON  rb.rn = re.rn + 1