2016-07-29 4 views
0

У меня есть таблица с несколькими идентификаторами. Каждый идентификатор имеет значения, упорядоченные последовательным индексом.SQL Server 2008: найти число смежных строк с равными значениями

create table myValues 
(
    id int, 
    ind int, 
    val int 
) 

insert into myValues 
values 
(21, 5, 300), 
(21, 4, 310), 
(21, 3, 300), 
(21, 2, 300), 
(21, 1, 345), 
(21, 0, 300), 
(22, 5, 300), 
(22, 4, 300), 
(22, 3, 300), 
(22, 2, 300), 
(22, 1, 395), 
(22, 0, 300) 

Я пытаюсь найти количество последовательных значений, которые являются одинаковыми.

Поле значения представляет некоторые данные, которые должны быть изменены для каждой записи (но не обязательно должны быть уникальными в целом).

Проблема заключается в том, чтобы узнать, когда имеется более двух последовательных строк с одинаковым значением (с учетом того же идентификатора).

Таким образом, я ищу выход, как это:

id ind val count 
21 5  300 1 
21 4  310 1 
21 3  300 2 
21 2  300 2 
21 1  345 1 
21 0  300 1 
22 5  300 4 
22 4  300 4 
22 3  300 4 
22 2  300 4 
22 1  395 1 
22 0  300 1 

Я знаю, это похоже на остров и зазорами проблемы обсуждались here.

Однако все эти решения зависят от возможности использования оператора раздела со значениями, которые должны последовательно увеличиваться.

Решение, которое генерирует диапазоны «островов» в качестве посредника, также будет работать, например.

id startind endind 
21 3   2 
22 5   2 

Обратите внимание, что для каждого идентификатора может быть много островов.

Я уверен, что есть простая адаптация решения для острова, но для жизни я не могу думать об этом.

+0

Пытались ли вы что-нибудь еще? –

+0

Я попытался использовать раздел с row_number() над каждой комбинацией строк, которые я мог придумать, чтобы получить индекс, который сбрасывается на каждое другое значение, но это не работает без переупорядочения. – sonarforte

+0

Результат, о котором вы сказали, не может быть сделано с вашими данными образца. Он лишен –

ответ

2

найти непрерывную группу, а затем сделать отсчет() раздел этой

select id, ind, val, count(*) over (partition by id, val, grp) 
from 
(
    select *, grp = dense_rank() over (partition by id, val order by ind) - ind 
    from myValues 
) d 
order by id, ind desc 
+0

Работал красиво ... Теперь мне нужно выяснить, как – sonarforte

0

Другое решение, очевидно, более элегантное. Мне придется изучить его немного ближе.

with agg(id, min_ind, max_ind, cnt) as (
    select id, min(ind), max(ind), count(*) 
    from 
     (
     select id, ind, val, sum(brk) over (partition by id order by ind desc) as grp 
     from 
      (
      select 
       id, ind, val, 
       coalesce(sign(lag(ind) over (partition by id, val order by ind desc) - ind - 1), 1) as brk 
      from myValues 
      ) as d 
     ) as d 
    group by id, grp 
) 
select v.id, v.ind, v.val, a.cnt 
from myValues v inner join agg a on a.id = v.id and v.ind between min_ind and max_ind 
order by v.id, v.ind desc;