2016-01-20 3 views
1

Предположим, у меня есть следующие записи:TSQL граф Последовательные записи

KeyCol  ColA  ColB 
------------------------ 
1   1  A 
2   2  B 
3   2  B 
4   2  C 
5   2  B 
6   1  A 
7   2  B 
8   2  B 

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

Col A  ColB  Start Count 
--------------------------------- 
1   A  1  1 
2   B  2  2 
2   C  4  1 
2   B  5  1 
1   A  6  1 
2   B  7  2 

Там много схожего вопросы по группировке и подсчету, но я не понимаю, как перевести его на этот. Особенно многие другие примеры не имеют явного ключевого столбца.

Я пытался использовать функцию секционирования для подсчета числа последовательных записей и взять его оттуда:

SELECT KeyCol, ColA, ColB 
     ,ROW_NUMBER() OVER 
      ( PARTITION 
       BY ColA, ColB 
       ORDER BY KeyCol 
      ) as RowNo 
FROM MyTable 

Однако, это производит этот результат:

KeyCol Col A  ColB  RowNo 
--------------------------------- 
1   1   A  1 
2   2   B  1 
3   2   B  2 
4   2   C  1 
5   2   B  3 (Needs to be 1) 
6   1   A  2 (Needs to be 1) 
7   2   B  4 (Needs to be 1) 
8   2   B  5 (Needs to be 2) 

Как вы можете видеть , число строк увеличивается для всех одинаковых ColA, ColB, даже если записи не являются последовательными.

спасибо!

+0

Вы что-то пробовали? Если у вас есть, отредактируйте запрос в свой вопрос. –

+1

Привет, спасибо, за ваш комментарий. Я просто добавил запрос, который я попробовал. – Roeland

ответ

4

Это Gaps and Islands problem. Вам нужно использовать функции ранжирования для идентификации групп (островов) одного значения для ColB. Следующий запрос:

SELECT KeyCol, 
     ColA, 
     ColB, 
     GroupBy = ROW_NUMBER() OVER(ORDER BY KeyCol) - 
        ROW_NUMBER() OVER(PARTITION BY ColA, ColB ORDER BY KeyCol) 
FROM dbo.T 
ORDER BY KeyCol; 

Вы получите вывод:

KeyCol  ColA  ColB GroupBy 
----------------------------------------- 
1   1  A   0 
2   2  B   1 
3   2  B   1 
4   2  C   3 
5   2  B   2 
6   1  A   4 
7   2  B   3 
8   2  B   3 

Как вы можете видеть, это определяет ваши острова, где два (или более) последовательные строки имеют одинаковые значения для колы и ColB , вы получите то же значение в столбце GroupBy.

Как только у вас есть это, это простой случай группировки, чтобы получить требуемый результат. Предоставление окончательного запроса (с данными примера):

DECLARE @T TABLE (KeyCol INT, ColA INT, ColB CHAR(1)); 
INSERT @T (KeyCol, ColA, ColB) 
VALUES 
    (1, 1, 'A'), (2, 2, 'B'), (3, 2, 'B'), (4, 2, 'C'), 
    (5, 2, 'B'), (6, 1, 'A'), (7, 2, 'B'), (8, 2, 'B'); 

WITH RankedData AS 
( SELECT KeyCol, 
      ColA, 
      ColB, 
      GroupBy = ROW_NUMBER() OVER(ORDER BY KeyCol) - 
         ROW_NUMBER() OVER(PARTITION BY ColA, ColB ORDER BY KeyCol) 
    FROM @T 
) 
SELECT ColA, 
     ColB, 
     Start = MIN(KeyCol), 
     [Count] = COUNT(*) 
FROM RankedData 
GROUP BY ColA, ColB, GroupBy 
ORDER BY Start; 
+0

Привет, Гарет, отличный ответ, спасибо! У меня только один вопрос: можете ли вы заставить его работать для случая, когда KeyCol имеет свои недостатки. Так скажите, что третья запись начинается с KeyCol = 4. Это та ситуация, с которой я столкнулся. Просто любопытно, я все еще могу использовать ваш ответ, имея промежуточный шаг, на котором создается таблица с последовательными значениями KeyCol. – Roeland

+0

@Roeland Извините, я делаю эту ошибку все время .... Я отредактировал ответ так теперь, вместо использования 'KeyCol - ROW_NUMBER() ...' для генерации идентификатора, теперь он использует дополнительную функцию ранжирования для генерации последовательность без пробелов для замены KeyCol. – GarethD

+0

Теперь это выглядит так просто, имея ответ под рукой :) Большое спасибо Гарет, не мог мечтать о таком быстром решении! – Roeland

Смежные вопросы