Merging data in a single SQL table without a Cursor

别来无恙 提交于 2019-12-02 18:41:17

The key observation is that a sequence of numbers minus another sequence is a constant. We can generate another sequence using row_number. This identifies all the groups:

select id, MIN(number) as low, MAX(number) as high
from (select t.*,
             (number - ROW_NUMBER() over (partition by id order by number) ) as groupnum
      from t
     ) t
group by id, groupnum

The rest is just aggregation.

Solution with CTE and recursion:

WITH CTE AS (
  SELECT T.ID, T.NUMBER, T.NUMBER AS GRP
  FROM T 
  LEFT OUTER JOIN T T2 ON T.ID = T2.ID AND T.NUMBER -1 = T2.NUMBER 
  WHERE T2.ID IS NULL
  UNION  ALL
  SELECT T.ID, T.NUMBER, GRP
  FROM CTE 
  INNER JOIN T
  ON T.ID = CTE.ID AND T.NUMBER  = CTE.NUMBER + 1
)
SELECT ID, MAX( NUMBER ), MIN(NUMBER)
FROM CTE
GROUP BY ID, GRP

Results at fiddlesql

I'd suggest using a WHILE loop structure with a table variable instead of the cursor.

For example,

DECLARE @TableVariable TABLE
(
    MyID int IDENTITY (1, 1) PRIMARY KEY NOT NULL,
    [ID] int,
    [Number] int
)

DECLARE @Count int, @Max int

INSERT INTO @TableVariable (ID, Number)
SELECT ID, Number
FROM YourSourceTable

SELECT @Count = 1, @Max = MAX(MyID)
FROM @TableVariable

WHILE @Count <= @Max
BEGIN

    ...do your processing here...


    SET @Count = @Count + 1

END
CREATE TABLE Table1
    ([ID] int, [Number] int)
;

INSERT INTO Table1
    ([ID], [Number])
VALUES
    (1, 25),
    (1, 26),
    (1, 30),
    (1, 24),
    (2, 4),
    (2, 8),
    (2, 5)
;

    select ID, 
           MIN(Number)
         ,(SELECT MIN(Number) 
                  FROM (SELECT TOP 2 Number from Table1 WHERE ID =
                  T1.Id ORDER BY Number DESC) as DT)
    from Table1 as T1
    GROUP BY ID
    UNION 
    SELECT ID, MAX(Number), MAX(Number)
    FROM Table1 as T1
    GROUP BY ID;

Live Example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!