Usando Row_Number para encontrar el recuento de filas consecutivas

8

Tengo esta columna de entradas que representa la aparición de una señal y estoy tratando de agregar una columna que muestre el recuento de filas consecutivas

Si mis datos se ven así

724
727
728
733
735
737
743
747
749

los datos resultantes con una columna de recuento de filas consecutivas se verían así

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

Lo hice usando una función de bucle, pero estoy tratando de resolverlo usando un cte. Aquí hay una muestra de mi último intento

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

Produce estos resultados

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

Al primer problema obvio le falta la primera señal de una serie. Salvo eso, pensé que podría pasar esto a otro cte con una partición row_number en el Marker consecutivo. Eso no funcionó porque lo particionó como una partición. No pude encontrar una manera de indicarle al método de partición que una serie está separada de la siguiente

Cualquier ayuda es apreciada.

NaranjaYoda
fuente
1
Parece haber una falta de coincidencia entre los datos de origen y los resultados deseados.
Martin Smith

Respuestas:

16

El nombre general para este tipo de consulta es "brechas e islas". Un enfoque a continuación. Si puede tener duplicados en los datos de origen, puede necesitar en dense_ranklugar derow_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

Devoluciones

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

En SQL 2012 también puede hacer esto usando LAG y las funciones de la ventana, por ej.

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
wBob
fuente
-1

Como es habitual con tales problemas, es muy fácil de lograr en Java o C ++ o C #.

Si realmente necesita hacerlo en la base de datos, puede usar un RDBMS con cursores rápidos, como Oracle, escribir un cursor simple y disfrutar de un rendimiento rápido sin tener que escribir nada complejo.

Si necesita hacerlo en T-SQL, y no puede cambiar el diseño de la base de datos, Itzik Ben-Gan ha escrito varias soluciones en "MVP Deep Dives vol 1", y algunas soluciones nuevas usando funciones OLAP en su nuevo libro sobre funciones de ventana en SQL 2012.

Alternativamente, puede agregar otra columna consecutivaMarker a su tabla y almacenar valores precalculados en ella. Podemos usar restricciones para asegurar que los datos precalculados siempre sean válidos. Si alguien está interesado, puedo explicar cómo.

Alaska
fuente