【问题标题】:Count Number of Consecutive Occurrence of values in Table统计表中值的连续出现次数
【发布时间】:2016-08-23 23:40:01
【问题描述】:

我有下表

create table #t (Id int, Name char)

insert into #t values
(1, 'A'),
(2, 'A'),
(3, 'B'),
(4, 'B'),
(5, 'B'),
(6, 'B'),
(7, 'C'),
(8, 'B'),
(9, 'B')

我想统计名称列中的连续值

+------+------------+
| Name | Repetition |
+------+------------+
| A    |          2 |
| B    |          4 |
| C    |          1 |
| B    |          2 |
+------+------------+

我尝试过的最好的事情是:

select Name
, COUNT(*) over (partition by Name order by Id) AS Repetition
from #t
order by Id

但它没有给我预期的结果

【问题讨论】:

  • 我也有同样的需求,但在google sheet里,哈哈

标签: sql sql-server tsql sql-server-2012 aggregation


【解决方案1】:

一种方法是行号的差异:

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

如果你运行子查询并分别查看每个行号的值然后查看差异,则逻辑最容易理解。

【讨论】:

  • 添加order by max(id)后,结果将与OP的帖子中的完全相同(涉及记录的顺序)。
  • @KingKing,感谢您的提示。是的,它完全符合我的需要。
  • 为什么我的查询没有给我结果,我希望当我按名称分区时,count(*) 应该在名称值更改时重置。如果你能解释一下,我很感激。再次感谢。
  • @FLICKER。 . .我想如果你运行你的查询,你应该明白。它枚举名称而不考虑行之间的间隙。也就是说,它忽略了差距。
  • @vijayraj34 我不认为自加入会给你这个特定的结果(任何值的连续出现)。自加入CAN给你每个记录组的极限(最大/最小,第一个/最后一个等)记录:stackoverflow.com/a/8749095/258598
【解决方案2】:

您可以使用 LAG 和运行总计等窗口函数:

WITH cte AS (
 SELECT Id, Name, grp = SUM(CASE WHEN Name = prev THEN 0 ELSE 1 END) OVER(ORDER BY id)
 FROM (SELECT *, prev = LAG(Name) OVER(ORDER BY id) FROM t) s
)
SELECT name, cnt = COUNT(*)
FROM cte
GROUP BY grp,name
ORDER BY grp;

db<>fiddle demo

第一个 cte 返回组号:

+-----+-------+-----+
| Id  | Name  | grp |
+-----+-------+-----+
|  1  | A     |   1 |
|  2  | A     |   1 |
|  3  | B     |   2 |
|  4  | B     |   2 |
|  5  | B     |   2 |
|  6  | B     |   2 |
|  7  | C     |   3 |
|  8  | B     |   4 |
|  9  | B     |   4 |
+-----+-------+-----+

主查询根据之前计算的grp 列对其进行分组:

+-------+-----+
| name  | cnt |
+-------+-----+
| A     |   2 |
| B     |   4 |
| C     |   1 |
| B     |   2 |
+-------+-----+

【讨论】:

    【解决方案3】:

    我使用了递归 CTE 并尽量减少 row_number 的使用,也避免使用 count(*)。

    我认为它会表现得更好,但在现实世界中,这取决于您放置的其他过滤器以最大限度地减少受影响的行数。

    如果 ID 具有离散值,则将使用一个额外的 CTE 来生成连续的 ID。

     ;With CTE2 as
    (
    select ROW_NUMBER()over(order by id) id, name,1 Repetition ,1 Marker  from @t
    )
    , CTE as
    (
    select top 1 cast(id as int) id, name,1 Repetition ,1 Marker  from CTE2 order by id
    
    union all
    
    select a.id, a.name
    , case when a.name=c.name then Repetition +1 else 1 end  
    , case when a.name=c.name then c.Marker else  Marker+1 end
    from @t a
    inner join CTE c on a.id=c.id+1
    
    )
    ,CTE1 as
    (select *,ROW_NUMBER()over(partition by marker order by id desc)rn from cte c
    )
    select Name,Repetition from cte1 where rn=1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多