【问题标题】:Generate all the continous intervals from a series从一系列中生成所有连续间隔
【发布时间】:2009-09-14 08:55:58
【问题描述】:

我有这个问题,我无法完全解决。我可以得到缺失的数字区间,但我无法将它们拼凑到我的连续系列中。

因此,如果我有一个定义为 [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  |

有人想分享一个聪明的解决方案吗?

编辑: 这是(可能是多余的)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。计划发生了变化,所以我不再需要这种解决方案。不过还是谢谢大家的回复!很有帮助:D

【问题讨论】:

    标签: tsql series


    【解决方案1】:

    简单的方法是创建一个带有 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)
    

    【讨论】:

      【解决方案2】:
      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
      

      【讨论】:

        【解决方案3】:

        试试这个

        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
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-11-25
          • 1970-01-01
          • 1970-01-01
          • 2013-03-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-03-13
          相关资源
          最近更新 更多