Как сгруппировать одинаковые значения в последовательности - PullRequest
0 голосов
/ 04 ноября 2019

Я пытаюсь сгруппировать данные в порядке следования. У меня есть следующая таблица:

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) из группы #temp по num

Мне нужно это:

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

Фактический результат:

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

Ответы [ 3 ]

4 голосов
/ 04 ноября 2019

Это проблема пробелов и островков. Вот один из способов ее решения с использованием 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

Демонстрация на БД Fiddlde :

num | count_num
--: | --------:
  1 |         3
  2 |         1
  1 |         1
  2 |         2
  3 |         3
1 голос
/ 04 ноября 2019

Проблемы с пробелами и островами - это весело, потому что есть много разных способов их решения. Вот один подход, который не требует агрегирования - хотя он требует более широкого использования оконных функций.

Это возможно, потому что единственная запрашиваемая вами информация - это счетчик. Если 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;

Здесь - это дБ. <> скрипка.

1 голос
/ 04 ноября 2019

Другой подход может использовать 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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...