查找连续序列并建议序列中的下一个数字

Posted

技术标签:

【中文标题】查找连续序列并建议序列中的下一个数字【英文标题】:Find consecutive sequence and suggest next number in sequence 【发布时间】:2021-12-09 15:52:33 【问题描述】:

我正在尝试创建一个程序,它将:

将任何数字作为输入,例如102 找到它所属的序列范围,例如100 to 103 向用户返回建议的下一个号码,例如104

表格本身看起来像这样:

Num
100
101
102
103
110
111
112
113
114
115
120
121

理想情况下,查询的输出会返回如下内容:

start end nextNr
100 103 104
110 115 116
120 121 122

我正在尝试做的这件事与某种间隙和孤岛技术有关。 我看了看从这里尝试一些东西,但无法让它发挥作用。 Gaps and Islands Link

这是我尝试过的……

WITH cteSource(ID, Seq, Num)
AS(
    SELECT d.ID, f.Seq, f.Num
    FROM (
        SELECT 
            ID,
            ROW_NUMBER() OVER (PARTITION BY ID ORDER BY MIN(SeqNo)) AS Grp,
            MIN(SeqNo) AS StartSeqNo,
            MAX(SeqNo) AS EndSeqNo
        FROM
            (
            SELECT 1 ID, Num SeqNo, 
               Num - ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY Num) AS RN
            FROM 
            Number
            ) AS a
        GROUP BY ID, RN
        ) d
    CROSS APPLY (
            VALUES (d.Grp, d.EndSeqNo + 1),(d.Grp -1, d.StartSeqNo -1)
            ) AS f(Seq, Num)
)
SELECT ID, MIN(Num) AS StartSeqNo, MAX(Num) AS EndSeqNo, MAX(Num) + 1 as NextNr
FROM cteSource
GROUP BY ID, Seq
HAVING COUNT(*) = 2

结果如下:

StartSeqNo EndSeqNo NextNr
104 109 110
116 119 120

设置如下:

CREATE TABLE [dbo].[Number](
    [Num] [int] NULL
) 
GO

INSERT INTO Number
(Num)
VALUES
(100),
(101),
(102),
(103),
(110),
(111),
(112),
(113),
(114),
(115),
(120),
(121)

【问题讨论】:

【参考方案1】:

也许这会有所帮助。

Select [Start]  = min(num)
      ,[End]    = max(num)
      ,[NextNr] = max(num) + 1
 From (
        Select * 
              ,Grp = num - row_number() over (order by num)
         From  number
      ) A
 Group By Grp

结果

Start   End     NextNr
100     103     104
110     115     116
120     121     122

【讨论】:

这真是……太棒了! 哇,这么简单...我如何确保NextNr 不会意外进入下一个序列?在我发布之后才意识到这可能会发生...... @Justin 如果 NextNr 可以进入下一个序列,这意味着那里没有间隙,并且结果序列看起来不会像那样。【参考方案2】:

您的第一个子查询可以很好地获取组以及开始和结束编号:

  SELECT 
            ROW_NUMBER() OVER (PARTITION BY ID ORDER BY MIN(SeqNo)) AS Grp,
            MIN(SeqNo) AS StartSeqNo,
            MAX(SeqNo) AS EndSeqNo
        FROM
            (
            SELECT 1 ID, Num SeqNo, 
               Num - ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY Num) AS RN
            FROM 
            Number
            ) AS a
        GROUP BY ID, RN

然后你就不必要地把它复杂化了,而不是仅仅为 NextNr 使用 EndSeqNo + 1:

WITH CTE_Groups AS 
(
        SELECT 
            ROW_NUMBER() OVER (PARTITION BY ID ORDER BY MIN(SeqNo)) AS Grp,
            MIN(SeqNo) AS StartSeqNo,
            MAX(SeqNo) AS EndSeqNo
        FROM
            (
            SELECT 1 ID, Num SeqNo, 
               Num - ROW_NUMBER() OVER (PARTITION BY 1 ORDER BY Num) AS RN
            FROM 
            Number
            ) AS a
        GROUP BY ID, RN
)
SELECT *, EndSeqNo + 1 AS NextNr 
FROM 
CTE_Groups

编辑:并进一步删除不必要的分区和额外的列

WITH CTE_Groups AS 
(
        SELECT 
            MIN(SeqNo) AS StartSeqNo,
            MAX(SeqNo) AS EndSeqNo
        FROM
            (
            SELECT  Num SeqNo, 
               Num - ROW_NUMBER() OVER (ORDER BY Num) AS RN
            FROM 
            Number
            ) AS a
        GROUP BY RN
)
SELECT *, EndSeqNo + 1 AS NextNr 
FROM 
CTE_Groups

【讨论】:

以上是关于查找连续序列并建议序列中的下一个数字的主要内容,如果未能解决你的问题,请参考以下文章

如何根据 SQL 中的时间戳查找特定事件的下一个序列?

LeetCode 128 最长连续序列

LeetCode 128 最长连续序列

在一个序列中找到相似的数字并记录最大连续条纹

查找数字序列中的空白

连续区间的二分查找