Menggunakan Row_Number untuk menemukan jumlah baris berturut-turut


8

Saya memiliki kolom int yang mewakili kemunculan sinyal dan saya mencoba menambahkan kolom yang menunjukkan jumlah baris berturut-turut

Jika data saya terlihat seperti ini

724
727
728
733
735
737
743
747
749

data yang dihasilkan dengan kolom jumlah baris berturut-turut akan terlihat seperti ini

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

Saya sudah melakukannya menggunakan fungsi looping tapi saya mencoba mencari tahu menggunakan cte. Berikut adalah contoh upaya terbaru saya

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

Menghasilkan hasil ini

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

Masalah pertama yang jelas adalah kehilangan sinyal pertama dalam suatu seri. Kecuali itu, saya pikir saya bisa meneruskan ini ke cte lain dengan mempartisi row_number pada consecutiveMarker. Itu tidak berhasil karena dipartisi sebagai satu partisi. Saya tidak dapat menemukan cara untuk menunjukkan ke metode partisi bahwa satu seri terpisah dari yang berikutnya

Bantuan apa pun dihargai.


1
Tampaknya ada ketidaksesuaian antara sumber data dan hasil yang diinginkan.
Martin Smith

Jawaban:


16

Nama umum untuk jenis kueri ini adalah "celah dan pulau". Satu pendekatan di bawah ini. Jika Anda dapat memiliki duplikat dalam sumber data, Anda mungkin perlu dense_rankdaripadarow_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

Kembali

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

1

Di SQL 2012 Anda juga bisa melakukan ini menggunakan LAG dan fungsi-fungsi jendela, misalnya

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

Seperti biasa dengan masalah seperti itu, sangat mudah dilakukan di Java atau C ++ atau C #.

Jika Anda benar-benar perlu melakukannya dalam database, Anda dapat menggunakan RDBMS dengan kursor cepat, seperti Oracle, menulis kursor sederhana, dan menikmati kinerja cepat tanpa harus menulis sesuatu yang rumit.

Jika Anda perlu melakukannya dalam T-SQL, dan Anda tidak dapat mengubah desain basis data, Itzik Ben-Gan telah menulis beberapa solusi dalam "MVP Deep Dives vol 1", dan beberapa solusi baru menggunakan fungsi OLAP dalam buku barunya tentang fungsi jendela dalam SQL 2012.

Atau, Anda bisa menambahkan kolom lain berturut-turutMarker ke tabel Anda, dan menyimpan nilai yang telah dihitung sebelumnya di dalamnya. Kami dapat menggunakan batasan untuk memastikan bahwa data yang dihitung sebelumnya selalu valid. Jika ada yang tertarik, saya bisa menjelaskan caranya.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.