Home > Back-end >  Find consecutive sequence and suggest next number in sequence
Find consecutive sequence and suggest next number in sequence

Time:12-10

I'm trying to create a procedure that will:

  • take any number as an input e.g. 102
  • find the sequence range it belongs e.g. 100 to 103
  • return a suggested next number to the user e.g. 104

The table itself will look something like this:

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

Ideally the output of the query would return something like this:

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

I this what I'm trying to do is linked to some kind of Gap and Island technique. I had a look at trying something from here but couldn't quite get it to work. Gaps and Islands Link

This is what I tried coming up with...

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

The result looks like this:

StartSeqNo EndSeqNo NextNr
104 109 110
116 119 120

Here's the setup:

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)

CodePudding user response:

Perhaps this will help.

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

Results

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

CodePudding user response:

Your first subquery works fine to get groups and start and end number:

  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

You just then needlessly complicated it instead of just using EndSeqNo 1 for NextNr:

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

EDIT: and with further removing unnecessary partitons and extra columns

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
  • Related