如何找到连续序列号组的边界?

Mik*_*ion 8 sql-server sql-server-2008 gaps-and-islands

我有一个表格,其中包含以下定义

CREATE TABLE mytable
  (
     id     INT IDENTITY(1, 1) PRIMARY KEY,
     number BIGINT,
     status INT
  )
Run Code Online (Sandbox Code Playgroud)

和示例数据

INSERT INTO mytable
VALUES (100,0),
       (101,0),
       (102,0),
       (103,0),
       (104,1),
       (105,1),
       (106,0),
       (107,0),
       (1014,0),
       (1015,0),
       (1016,1),
       (1017,0)
Run Code Online (Sandbox Code Playgroud)

仅查看status = 0如何将Number值折叠为连续序列号范围并查找每个范围的开始和结束的行?

即对于示例数据,结果将是

         FROM      to 
Number    100      103
Number    106      107
Number    1014     1015
Number    1017     1017
Run Code Online (Sandbox Code Playgroud)

Mar*_*ith 27

正如评论中所提到的,这是一个典型的差距和岛屿问题.

由Itzik Ben Gan推广的解决方案是使用ROW_NUMBER() OVER (ORDER BY number) - number在"岛屿"内保持不变并且不能出现在多个岛屿中的事实.

WITH T
     AS (SELECT ROW_NUMBER() OVER (ORDER BY number) - number AS Grp,
                number
         FROM   mytable
         WHERE  status = 0)
SELECT MIN(number) AS [From],
       MAX(number) AS [To]
FROM   T
GROUP  BY Grp
ORDER  BY MIN(number) 
Run Code Online (Sandbox Code Playgroud)

注意:如果number不能保证是唯一的替换ROW_NUMBERDENSE_RANK上面的代码.

  • 这是Itzak谈论它的地方之一:http://www.sqlmag.com/article/tsql3/calculating-concurrent-sessions-part-3.我不会提到他为解决这个问题而归功于谁(除了Ben Flanaghan和Arnold Fribble).;-) (3认同)
  • @MikeStation - 与什么相反?`GRP` 值需要在一个岛内保持不变,并且对于实现它的岛来说是唯一的。例如,在此处查看结果并尝试更改示例数据,您应该会看到它是如何工作的。http://sqlfiddle.com/#!6/f1040/2 (2认同)