Как группировать по непрерывным записям в SQL - PullRequest
1 голос
/ 28 мая 2020

В моей таблице есть эти записи

ID  Colour
------------
 1   Red
 2   Red
 3   Red
 4   Red
 5   Red
 6   Green
 7   Green
 8   Green
 9   Green
10   Red
11   Red
12   Red
13   Red
14   Green
15   Green
16   Green
17   Blue
18   Blue
19   Red
20   Blue

Я могу легко сгруппировать по цвету вот так

SELECT Colour, MIN(ID) AS iMin, MAX(ID) AS iMax
FROM MyTable
GROUP BY Colour

Это вернет этот результат

Colour     iMin     iMax
-------------------------
Red        1        19
Green      6        16
Blue       17       20

Но это это не то, что я хочу, так как красный не go от 1 до 19, зеленый прерывает последовательность.

Результат должен быть таким

Colour     iMin     iMax
------------------------
Red        1        5
Green      6        9
Red        10       13
Green      14       16
Blue       17       18
Red        19       19
Blue       20       20

Мне удалось сделать это курсором, но интересно, есть ли более эффективный способ сделать это

Ответы [ 3 ]

2 голосов
/ 28 мая 2020

Это проблема промежутков и островов. Вы можете решить эту проблему с помощью разницы номеров строк:

select colour, min(id), max(id)
from (select t.*,
             row_number() over (order by id) as seqnum,
             row_number() over (partition by colour order by id) as seqnum_c
      from t
     ) t
group by colour, (seqnum - seqnum_c);

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

Немного сложно объяснить, как это работает . Однако, если вы посмотрите на результаты подзапроса, вы увидите, как разница номеров строк определяет соседние цвета.

2 голосов
/ 28 мая 2020

Это проблема промежутков и островов. Предполагая, что id непрерывно увеличивается, вы можете использовать разницу между row_number() для определения групп «смежных» записей, имеющих одинаковые colour:

select 
    colour, 
    min(id) iMin,
    max(id) iMax
from (
    select t.*, row_number() over(partition by colour order by id) rn
    from mytable t
) t
group by colour, id - rn
order by min(id)

Демо на DB Fiddle :

colour | iMin | iMax
:----- | ---: | ---:
Red    |    1 |    5
Green  |    6 |    9
Red    |   10 |   13
Green  |   14 |   16
Blue   |   17 |   18
Red    |   19 |   19
Blue   |   20 |   20
0 голосов
/ 28 мая 2020

Запрос действителен независимо от того, является ли столбец id целым числом, а значение столбца id непрерывным.

;with c0 as(
select id, color,
       ROW_NUMBER() over(order by id)*
       (case when color <> LAG(color, 1, '') over(order by id) then 1 else 0 end) as color_id
from #temp
), c1 as(
select id, color, color_id, SUM(color_id) over(order by id) as color_gid
from c0
)
select color, MIN(id) as idMin, MAX(id) as idMax
from c1
group by color, color_gid

Его можно расширить для сортировки по столбцу a, группировки по последовательным значениям столбец b и найдите совокупные значения для столбца c, например:

;with c0 as(
select C, B,
       ROW_NUMBER() over(order by A)*
       (case when B <> LAG(B, 1, '') over(order by A) then 1 else 0 end) as B_id
from TableName
), c1 as(
select C, B, B_id, SUM(B_id) over(order by A) as B_gid
from c0
)
select B, MIN(C) as CMin, MAX(C) as CMax
from c1
group by B, B_gid
...