SQL中的序列分组

时间:2012-07-06 14:30:35

标签: sql sql-server tsql grouping

我正在尝试按顺序对数据进行分组。说我有下表:

| 1 | A |
| 1 | A |
| 1 | B |
| 1 | B |
| 1 | C |
| 1 | B |

我需要SQL查询来输出以下内容:

| 1 | A | 1 |
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | B | 2 |
| 1 | C | 3 |
| 1 | B | 4 |

最后一列是在每个组中递增的组编号​​。需要注意的重要一点是,第3,4和5行包含的数据应该分为2组而不是1组。

3 个答案:

答案 0 :(得分:1)

这将为您提供列上的排名。 但它不会给你1,2,3。 它将根据每个分组中的数量为您提供1,3,6等

select 
a,
b,
rank() over (order by a,b)
 from
table1

请参阅此SQLFiddle以更清楚地了解我的意思:http://sqlfiddle.com/#!3/0f201/2/0

答案 1 :(得分:1)

你想要的正常方式是dense_rank函数:

select key, val,
       dense_rank() over (order by key, val)
from t

但是,这并没有解决分离最后一组的问题。

要处理这个问题,我必须假设有一个“id”列。 SQL中的表没有排序,所以我需要排序。如果您使用的是SQL Server 2012,则可以使用lag()函数来获取所需内容。使用滞后来查看连续行上的key,val对是否相同:

with t1 as (
     select id, key, val,
            (case when key = lead(key, 1) over (order by id) and
                       val = lead(val, 1) over (order by id)
                  then 1
                  else 0
             end) as SameAsNext
     from t
    )
select id, key, val,
       sum(SameAsNext) over (order by id) as GroupNum
from t

如果没有SQL Server 2012(具有累积总和),您必须执行自联接以识别每个组的开头:

select t.*,
from t left outer join
     t tprev
     on t.id = t2.id + 1 and t.key = t2.key and t.val = t2.val
where t2.id is null

使用此选项,使用连接将组指定为最小ID:

select t.id, t.key, t.val,
       min(tgrp.id) as GroupId
from t left outer join
     (select t.*,
      from t left outer join
           t tprev
           on t.id = t2.id + 1 and t.key = t2.key and t.val = t2.val
      where t2.id is null
    ) tgrp
    on t.id >= tgrp.id

如果您希望这些是连续的数字,那么将它们放在子查询中并使用dense_rank()。

答案 2 :(得分:1)

MSSQL2008

假设您有一个SampleStatuses表:

Status  Date
A       2014-06-11
A       2014-06-14
B       2014-06-25
B       2014-07-01
A       2014-07-06
A       2014-07-19
B       2014-07-21
B       2014-08-13
C       2014-08-19

你写下以下内容:

;with
cte as (
    select ROW_NUMBER() over(order by Date) as RowNumber,
    [Status], [Date] from SampleStatuses
),
cte2 as (
    select top 1 RowNumber, 1 as GroupNumber, [Status], [Date] from cte order by RowNumber
    union all
    select c1.RowNumber,
        case when c2.Status <> c1.Status then c2.GroupNumber + 1 else c2.GroupNumber end as  GroupNumber, c1.[Status], c1.[Date] 
    from cte2 c2 join cte c1 on c1.RowNumber = c2.RowNumber + 1     
)
select * from cte2;

你得到这个结果:

RowNumber   GroupNumber Status  Date
1           1           A       2014-06-11
2           1           A       2014-06-14
3           2           B       2014-06-25
4           2           B       2014-07-01
5           3           A       2014-07-06
6           3           A       2014-07-19
7           4           B       2014-07-21
8           4           B       2014-08-13
9           5           C       2014-08-19
相关问题