Использование Row_Number для поиска последовательного количества строк


8

У меня есть этот столбец целых, которые представляют возникновение сигнала, и я пытаюсь добавить столбец, который показывает количество последовательных строк

Если мои данные выглядят так

724
727
728
733
735
737
743
747
749

результирующие данные с последовательным столбцом подсчета строк будут выглядеть следующим образом

724 1
727 1
728 2
729 3
735 1
737 1
743 1
744 2
748 1

Я сделал это с помощью функции зацикливания, но я пытаюсь выяснить, используя cte. Вот образец моей последней попытки

DECLARE @d TABLE ( signal INT )
INSERT  INTO @d
        SELECT  724
        UNION
        SELECT  727
        UNION
        SELECT  728
        UNION
        SELECT  729
        UNION
        SELECT  735
        UNION
        SELECT  737
        UNION
        SELECT  743
        UNION
        SELECT  744
        UNION
        SELECT  748 ;
WITH    a AS ( SELECT   signal,
                        ROW_NUMBER() OVER ( ORDER BY signal ) AS marker
               FROM     @d
             ) ,
        b AS ( SELECT   a1.signal,
                        CASE ( a1.signal - a2.signal )
                          WHEN 1 THEN 1
                          ELSE 0
                        END consecutiveMarker
               FROM     a a1
                        INNER JOIN a a2 ON a2.marker = a1.marker - 1
             )
    SELECT  *
    FROM    b

Производит эти результаты

signal  consecutiveMarker
727 0
728 1
729 1
735 0
737 0
743 0
744 1
748 0

Первая очевидная проблема - отсутствие первого сигнала в серии. За исключением этого, я подумал, что смогу затем передать это другому cte с разделением row_number на последовательном маркере. Это не сработало, потому что разделило его на один раздел. Я не смог найти способ указать методу разделения, что одна серия отделена от следующей

Любая помощь приветствуется.


1
Кажется, существует несоответствие между исходными данными и желаемыми результатами.
Мартин Смит

Ответы:


16

Общее название для этого типа запроса "пробелы и острова". Один подход ниже. Если у вас могут быть дубликаты в исходных данных, которые вам могут понадобиться, dense_rankа неrow_number

WITH DATA(C) AS
(
SELECT 724 UNION ALL
SELECT 727 UNION ALL
SELECT 728 UNION ALL
SELECT 729 UNION ALL
SELECT 735 UNION ALL
SELECT 737 UNION ALL
SELECT 743 UNION ALL
SELECT 744 UNION ALL
SELECT 747 UNION ALL
SELECT 749
), T1 AS
(
SELECT C,
       C - ROW_NUMBER() OVER (ORDER BY C) AS Grp
FROM DATA)
SELECT C,
       ROW_NUMBER() OVER (PARTITION BY Grp ORDER BY C) AS Consecutive
FROM T1

Возвращает

C           Consecutive
----------- --------------------
724         1
727         1
728         2
729         3
735         1
737         1
743         1
744         2
747         1
749         1

1

В SQL 2012 вы также можете сделать это, используя LAG и оконные функции, например

DECLARE @d TABLE ( signal INT PRIMARY KEY) 

INSERT INTO @d 
VALUES
    ( 724 ),
    ( 727 ),
    ( 728 ),
    ( 729 ),
    ( 735 ),
    ( 737 ),
    ( 743 ),
    ( 744 ),
    ( 748 )

SELECT signal
    , 1 + ( SUM( is_group ) OVER ( ORDER BY signal ROWS BETWEEN 1 PRECEDING AND 0 FOLLOWING ) * is_group )
FROM
    (
    SELECT *
        , CASE WHEN LAG(signal) OVER( ORDER BY signal ) = signal - 1 THEN 1 ELSE 0 END is_group
    FROM @d
    ) x

-1

Как обычно с такими проблемами, это очень легко сделать в Java или C ++ или C #.

Если вам действительно нужно сделать это в базе данных, вы можете использовать СУБД с быстрыми курсорами, такими как Oracle, написать простой курсор и наслаждаться быстрой производительностью без необходимости писать что-либо сложное.

Если вам нужно сделать это в T-SQL, и вы не можете изменить дизайн базы данных, Ицик Бен-Ган написал несколько решений в «MVP Deep Dives vol 1», а также несколько новых решений, использующих функции OLAP, в своей новой книге о оконных функциях в SQL 2012

Кроме того, вы можете добавить в таблицу еще один столбец последовательный маркер и сохранить в нем предварительно рассчитанные значения. Мы можем использовать ограничения, чтобы гарантировать, что предварительно рассчитанные данные всегда действительны. Если кому-то интересно, могу объяснить как.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.