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

时间:2013-06-11 14:08:14

标签: sql-server sql-server-2008 gaps-and-islands

我有一个包含以下定义的表

CREATE TABLE mytable
  (
     id     INT IDENTITY(1, 1) PRIMARY KEY,
     number BIGINT,
     status INT
  )

和示例数据

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)

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

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

         FROM      to 
Number    100      103
Number    106      107
Number    1014     1015
Number    1017     1017

1 个答案:

答案 0 :(得分:25)

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

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) 

注意:如果number不能保证是唯一的,请在上面的代码中将ROW_NUMBER替换为DENSE_RANK