从sql查询中查找序列

时间:2015-11-27 14:52:31

标签: sql sql-server

你能帮我找到Active为真的序列中的第一个和最后一个id。所以从这个结果

id  |   Active
---------------
1   |   false
2   |   false
3   |   true
4   |   true
5   |   false
6   |   false
7   |   false
8   |   true
9   |   true
10  |   false
11  |   false
12  |   true
13  |   true
14  |   true

我需要所有连续序列(其中active为true),包含start和end id

startId   |   endId
------------------------
3         |   4
8         |   9
12        |   14

2 个答案:

答案 0 :(得分:6)

您可以使用岛屿解决方案执行此操作:

DECLARE @t TABLE
    (
      id INT ,
      Active VARCHAR(10)
    )

INSERT  INTO @t
VALUES  ( 1, 'false' ),
        ( 2, 'false' ),
        ( 3, 'true' ),
        ( 4, 'true' ),
        ( 5, 'false' ),
        ( 6, 'false' ),
        ( 7, 'false' ),
        ( 8, 'true' ),
        ( 9, 'true' ),
        ( 10, 'false' ),
        ( 11, 'false' ),
        ( 12, 'true' ),
        ( 13, 'true' ),
        ( 14, 'true' );
WITH    cte
          AS ( SELECT   * ,
                        ROW_NUMBER() OVER ( ORDER BY id )
                        - ROW_NUMBER() OVER ( PARTITION BY Active ORDER BY id ) rn
               FROM     @t
             )
    SELECT  MIN(id) AS StartID ,
            MAX(id) AS EndID
    FROM    cte
    WHERE   Active = 'true'
    GROUP BY rn

背后的想法是你只需要为岛屿分配一些值。看看你在cte中获得了什么:

id  Active  rn
1   false   0
2   false   0

3   true    2
4   true    2

5   false   2
6   false   2
7   false   2

8   true    5
9   true    5

10  false   4
11  false   4

12  true    7
13  true    7
14  true    7

答案 1 :(得分:5)

这是典型的间隙和岛屿问题。使用ROW_NUMBER标识具有相同Active值的连续记录组:

SELECT MIN(id) AS startId, MAX(id) AS endId
FROM (
  SELECT id, Active,
         ROW_NUMBER() OVER (ORDER BY id) -
         ROW_NUMBER() OVER (PARTITION BY Active ORDER BY id) AS grp
  FROM mytable) AS t
WHERE Active = 'true'
GROUP BY grp

外部查询只会根据Active = false计算字段过滤掉grp条记录和分组,以便获得startIdendId

Demo here