SQL Server 如何对按顺序排列的相同值进行分组

vql8enpb  于 2023-01-20  发布在  其他
关注(0)|答案(3)|浏览(292)

我试着按顺序对数据进行分组。我有下面的表:

id  num
-------
1   1
2   1
3   1
4   2
5   1
6   2
7   2
8   4
9   4
10  4

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

num       count(num)
-------------------    
1          3    
2          1    
1          1    
2          2    
4          3

样本数据:

select * into #temp 
from (
    select 1 as id, 1 as num union all
    select 2,  1  union all
    select 3,  1  union all
    select 4,  2  union all
    select 5,  1  union all
    select 6,  2  union all
    select 7,  2  union all
    select 8,  4  union all
    select 9,  4  union all
    select 10, 4 
) as abc
select * from #temp

按数值从#临时组中选择数值、计数(数值)
我需要这个:

num       count(num)    
-------------------    
1          3    
2          1    
1          1    
2          2    
4          3

实际输出:

num    count(num)    
---------------------    
1       4    
2       3    
4       3
roqulrg3

roqulrg31#

这是一个间隙和孤岛问题。下面是使用lag()和累积sum()解决该问题的一种方法:

select min(num) num, count(*) count_num
from (
    select t.*, sum(case when num = lag_num then 0 else 1 end) over(order by id) grp
    from (
        select t.*, lag(num) over(order by id) lag_num
        from #temp t
    ) t
) t
group by grp

Demo on DB Fiddlde

num | count_num
--: | --------:
  1 |         3
  2 |         1
  1 |         1
  2 |         2
  3 |         3
vyswwuz2

vyswwuz22#

另一种方法是使用row_number

select num, count(*) 
       from (select t.*,
             (row_number() over (order by id) -
              row_number() over (partition by num order by id)
             ) as grp
             from #temp t
            ) t
group by grp, num;

DBFIDDLE

x9ybnkn6

x9ybnkn63#

间隙和孤岛问题很有趣,因为有很多不同的方法可以解决它们。这里有一种不需要聚合的方法--尽管它需要更多地使用窗口函数。
这是可能的,因为您请求的唯一信息是计数。如果id没有间隙并且是连续的:

select num,
      lead(id, 1, max_id + 1) over (order by id) - id
from (select t.*,
             lag(num) over (order by id) as prev_num,
             max(id) over () as max_id
      from temp t
     ) t
where prev_num is null or prev_num <> num
order by id;

否则,您可以轻松地生成这样的序列:

select num,
      lead(seqnum, 1, cnt + 1) over (order by id) - seqnum
from (select t.*,
             lag(num) over (order by id) as prev_num,
             row_number() over (order by id) as seqnum,
             count(*) over () as cnt
      from temp t
     ) t
where prev_num is null or prev_num <> num
order by id;

Here是db〈〉小提琴。

相关问题