计算表中连续出现的值的数量

FLI*_*KER 17 t-sql sql-server aggregation sql-server-2012

我在桌子下面

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')
Run Code Online (Sandbox Code Playgroud)

我想在name列中计算连续值

+------+------------+
| Name | Repetition |
+------+------------+
| A    |          2 |
| B    |          4 |
| C    |          1 |
| B    |          2 |
+------+------------+
Run Code Online (Sandbox Code Playgroud)

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

select Name
, COUNT(*) over (partition by Name order by Id) AS Repetition
from #t
order by Id
Run Code Online (Sandbox Code Playgroud)

但它没有给我预期的结果

Gor*_*off 22

一种方法是行数的差异:

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;
Run Code Online (Sandbox Code Playgroud)

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

  • 添加 `order by max(id)` 后,结果将与 OP 的帖子完全一样(涉及记录的顺序)。 (2认同)

Luk*_*zda 7

您可以使用窗口函数,例如LAG和 running total:

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;
Run Code Online (Sandbox Code Playgroud)

db<>小提琴演示

第一个 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 |
+-----+-------+-----+
Run Code Online (Sandbox Code Playgroud)

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

+-------+-----+
| name  | cnt |
+-------+-----+
| A     |   2 |
| B     |   4 |
| C     |   1 |
| B     |   2 |
+-------+-----+
Run Code Online (Sandbox Code Playgroud)