Генерация всех непрерывных интервалов из серии - PullRequest
0 голосов
/ 14 сентября 2009

У меня есть проблема, которую я не могу решить. Я могу получить интервал пропущенных чисел, но я не могу собрать их обратно из моей непрерывной серии.

Итак, если у меня есть ряд, определенный как [1000,1001,1002,1003,1005,1006,1008], я хочу извлечь три непрерывных ряда [1000,1001,1002,1003] и [1005,1006] и [1008]. Используя простой CTE, я получил 1003, 1005, 1006 и 1008, так что я могу получить конец и начало интервалов, но что теперь?

В конце я хочу таблицу, которая выглядит следующим образом:

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

У кого-нибудь есть умное решение, которым они хотят поделиться?

EDIT: Вот (возможно, избыточный) 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 

РЕДАКТИРОВАТЬ 2: Ofc. произошла смена планов, поэтому мне больше не нужно такое решение. Спасибо за все ответы, хотя! Очень полезно: D

Ответы [ 3 ]

0 голосов
/ 14 сентября 2009

Попробуйте это

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 голосов
/ 14 сентября 2009
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
0 голосов
/ 14 сентября 2009

Самый простой выход - это иметь таблицу с номерами TaxLabelNumbers, чтобы вы могли выполнить внешнее объединение.

Можно также создать такую ​​таблицу в CTE, но она не очень эффективна.

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

CTE по умолчанию мудро использует 100 рекурсий, поэтому вам нужно проверить это, если вам нужно более 100 чисел:

select * from TaxLabelSeq option (MaxRecursion 4711)
...