0

我有下表:

|id|sog|zoneId|
| 1| 20|     2|
| 2|  2|     2|
| 3| 10|     2|
| 4| 10|     1|
| 5|  3|     1|
| 6| 8 |     2|
| 7| 1 |     2|
| 8| 3 |     2|
| 9| 4 |     2|

行按id列排序。

我想查询返回:

|id|sog|zoneId|grpId|
| 1| 20|     2|    1|
| 2|  2|     2|    1|
| 3| 10|     2|    1|
| 4| 10|     1|    2|
| 5|  3|     1|    2|
| 6| 8 |     2|    3|
| 7| 1 |     2|    3|
| 8| 3 |     2|    3|
| 9| 4 |     2|    3|
4

2 回答 2

2

这是一个基于Itzik Ben-Gan 解决岛屿和差距的解决方案

;with q as (
    select *,
           row_number() over (order by id)
         - row_number() over (order by zoneid, id) as grp
      from thetable
)
select id, sog, zoneid,
       min (id) over(partition by zoneid, grp) as grp
  from q
 order by id

Grp保持与两个序列相同,idZoneID, id继续运行,但数字既不有序也不连续。有序组号只需通过每组取 min(id) 来构造。如果您需要顺序组号,请添加另一个检索dense_rank() over(order by grp).

Sql Fiddle 这种方式。(感谢 w0lf)。

于 2013-08-12T09:11:34.600 回答
1

如果您的 ID 是连续的并且没有间隙,那么我认为最快的方法是:

;with cte as (
    select
        T.id, T.sog, T.zoneId,
        1 as grpId
    from Table1 as T
    where T.id = 1

    union all

    select
        T.id, T.sog, T.zoneId,
        c.grpId + case when T.zoneId = c.zoneId then 0 else 1 end as grpId
    from cte as c
        inner join Table1 as T on T.id = c.id + 1
)
select c.id, c.sog, c.zoneId, c.grpId
from cte as c

sql 小提琴演示

如果 Id 不是连续的或确实有间隙,您可以执行以下操作:

;with cte1 as (
    select
        T.id, T.sog, T.zoneId,
        row_number() over (order by T.id) as row_num
    from Table1 as T
), cte2 as (
    select
        T.id, T.sog, T.zoneId, T.row_num,
        1 as grpId
    from cte1 as T
    where T.row_num = 1

    union all

    select
        T.id, T.sog, T.zoneId, T.row_num,
        c.grpId + case when T.zoneId = c.zoneId then 0 else 1 end as grpId
    from cte2 as c
        inner join cte1 as T on T.row_num = c.row_num + 1
)
select c.id, c.sog, c.zoneId, c.grpId
from cte2 as c

sql 小提琴演示

但我不确定性能是否对此有好处

于 2013-08-12T06:28:52.750 回答