Utilizzo di Row_Number per trovare il conteggio delle righe consecutive


8

Ho questa colonna di ints che rappresenta un'occorrenza di un segnale e sto provando ad aggiungere una colonna che mostra il conteggio della riga consecutiva

Se i miei dati si presentano così

724
727
728
733
735
737
743
747
749

i dati risultanti con una colonna di conteggio di riga consecutiva sarebbero così

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

L'ho fatto usando una funzione di looping ma sto cercando di capire usando un cte. Ecco un esempio del mio ultimo tentativo

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 questi risultati

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

Nel primo ovvio problema manca il primo segnale di una serie. A parte questo, ho pensato di poterlo passare ad un altro cte con un partizionamento row_number sul Marker consecutivo. Non ha funzionato perché lo ha partizionato come una partizione. Non sono riuscito a trovare un modo per indicare al metodo di partizionamento che una serie è separata dalla successiva

Qualsiasi aiuto è apprezzato.


1
Sembra esserci una discrepanza tra i dati di origine e i risultati desiderati.
Martin Smith,

Risposte:


16

Il nome generale per questo tipo di query è "lacune e isole". Un approccio di seguito. Se puoi avere duplicati nei dati di origine potresti aver bisogno dense_rankpiuttosto cherow_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

ritorna

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

1

In SQL 2012 è anche possibile farlo utilizzando LAG e le funzioni della finestra, ad es

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

Come al solito con tali problemi, è molto facile da realizzare in Java, C ++ o C #.

Se hai davvero bisogno di farlo nel database, puoi usare un RDBMS con cursori veloci, come Oracle, scrivere un semplice cursore e goderti prestazioni veloci senza dover scrivere nulla di complesso.

Se è necessario farlo in T-SQL e non è possibile modificare la progettazione del database, Itzik Ben-Gan ha scritto diverse soluzioni in "MVP Deep Dives vol 1" e alcune nuove soluzioni che utilizzano le funzioni OLAP nel suo nuovo libro sulle funzioni delle finestre in SQL 2012.

In alternativa, è possibile aggiungere un'altra colonna consecutiveMarker alla tabella e archiviare valori precalcolati in essa. Possiamo utilizzare i vincoli per garantire che i dati precalcolati siano sempre validi. Se qualcuno è interessato, posso spiegare come.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.