TSQL中的序列分组

TSQL中的序列分组,sql,sql-server,tsql,grouping,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 | ;with cte as ( select ROW_NUMBER() over(order by Date) as R

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

| 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 |
;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;

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

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

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

请看这个SQLFiddle,以更清楚地了解我的意思:

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

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

查看此SQLFiddle以更清楚地了解我的意思:

您通常会使用稠密的秩函数:

select key, val,
       dense_rank() over (order by key, val)
from t
然而,这并不能解决将最后一组分开的问题

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

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

如果希望这些数字是连续的,则将它们放入子查询中,并使用densite_-rank()。

通常的做法是使用densite_-rank函数:

select key, val,
       dense_rank() over (order by key, val)
from t
然而,这并不能解决将最后一组分开的问题

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

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

如果希望这些是连续的数字,请将它们放入子查询中,并使用稠密的_rank()。

用于MSSQL2008

假设您有一个SampleStatus表:

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
你可以写以下内容:

| 1 | A | 1 |
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | B | 2 |
| 1 | C | 3 |
| 1 | B | 4 |
;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;

对于MSSQL2008:

假设您有一个SampleStatus表:

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
你可以写以下内容:

| 1 | A | 1 |
| 1 | A | 1 |
| 1 | B | 2 |
| 1 | B | 2 |
| 1 | C | 3 |
| 1 | B | 4 |
;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;

表是否具有唯一标识符?除非有办法区分表中行的顺序,否则无法可靠地做到这一点。如上所述,如果该表是一个堆,然后添加一个聚集索引,则可以/应该得到不同的结果。您需要提供更多信息。您的意思是第3、4和6行包含相同的数据。永远不要依赖于表数据的存储方式。SQL不是这样工作的。即使您确信SQLServer2005总是以某种方式存储数据,但这并不意味着2008年也会这样,或者2014年也会这样。如果您想要一个特定的顺序,那么您需要在列中设置该表是否具有唯一标识符(例如使用时间戳)?除非有办法区分表中行的顺序,否则无法可靠地进行设置。如上所述,如果该表是一个堆,然后添加一个聚集索引,则可以/应该得到不同的结果。您需要提供更多信息。您的意思是第3、4和6行包含相同的数据。永远不要依赖于表数据的存储方式。SQL不是这样工作的。即使您确信SQLServer2005总是以某种方式存储数据,但这并不意味着2008年也会这样,或者2014年也会这样。如果你想要一个特定的顺序,那么你需要在一列中设置它(可能使用时间戳),不幸的是,这不太管用,因为
b
不是他的“顺序”键(未定义或缺少)。很好地捕捉到了x-zero。我在订单上添加了一个似乎有效的。不幸的是,他的钥匙完全丢失了。如果你仔细观察他的期望结果,你应该注意到他期望最后一个
'B'
出现在
'C'
之后-你指定的
顺序将导致它出现在
'C'
之前。OP似乎依赖于表中数据的顺序,这充其量只是一种幻觉。不幸的是,这不太管用,因为
b
不是他的“顺序”键(未定义或缺失)。很好地捕捉到了x-zero。我在订单上添加了一个似乎有效的。不幸的是,他的钥匙完全丢失了。如果你仔细观察他的期望结果,你应该注意到他期望最后一个
'B'
出现在
'C'
之后-你指定的
顺序将导致它出现在
'C'
之前。OP似乎依赖于表中数据的顺序,这充其量只是一种错觉。