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似乎依赖于表中数据的顺序,这充其量只是一种错觉。