【问题标题】:How to group the same values which is in sequence order如何对按顺序排列的相同值进行分组
【发布时间】:2019-11-04 10:59:56
【问题描述】:

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

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) 来自#temp 按数量分组

我需要这个:

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

实际输出:

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

【问题讨论】:

  • 您已经告诉我们您“需要”什么,但您没有告诉我们您的问题。你在这里问什么? (不,“请为我编写 SQL”不是问题。)到目前为止,您尝试了哪些方法,为什么没有成功?
  • 我建议搜索空白和孤岛问题。

标签: sql sql-server tsql window-functions gaps-and-islands


【解决方案1】:

这是一个空白和孤岛问题。这是使用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:

编号 | count_num --: | --------: 1 | 3 2 | 1 1 | 1 2 | 2 3 | 3

【讨论】:

    【解决方案2】:

    另一种方法可以使用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

    【讨论】:

      【解决方案3】:

      差距和孤岛问题很有趣,因为有很多不同的方法可以解决它们。这是一种不需要聚合的方法——尽管它确实需要更多地使用窗口函数。

      这是可能的,因为您请求的唯一信息是计数。如果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 是一个 dbfiddle。

      【讨论】:

      • 这也是一个不错的解决方案!
      猜你喜欢
      • 2023-01-19
      • 1970-01-01
      • 2011-02-03
      • 2016-02-10
      • 1970-01-01
      • 2015-06-04
      • 2013-08-07
      • 1970-01-01
      • 2019-08-18
      相关资源
      最近更新 更多