Peter Larsson Blog

Patron Saint of Lost Yaks

Calculating Running Streak over many records

It has come to my attention that sometimes there are more than 100,000 records for which a "running streak" should be calculated on, so my previous blog post http://weblogs.sqlteam.com/peterl/archive/2009/08/12/Another-running-streaks-algorithm.aspx will not do.
But this will work, and work fast!

DECLARE  @Sample TABLE
        (
            Col1 INT,
            Col2 INT,
            Col3 INT,
            Col4 INT,
            Col5 INT,
            Col6 INT,
            Col7 INT,
            Col8 DATETIME
        )

INSERT  @Sample
SELECT  43, 12345, 99887, 0, 0, 0, 0, '8/10/2009 6:00' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 0, '8/10/2009 6:05' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 1, '8/10/2009 6:10' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 1, '8/10/2009 6:15' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 1, '8/10/2009 6:20' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 0, '8/10/2009 6:25' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 0, '8/10/2009 6:30' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 1, '8/10/2009 6:35' UNION ALL
SELECT  43, 12345, 99887, 0, 0, 0, 0, '8/10/2009 6:40'

SELECT      w.Col7,
            MIN(w.Col8)
FROM        (
                SELECT  Col7,
                        Col8,
                        ROW_NUMBER() OVER (ORDER BY Col8) AS recID
                FROM    @Sample
            ) AS w
INNER JOIN  (
                SELECT  Col7,
                        Col8,
                        ROW_NUMBER() OVER (PARTITION BY Col7 ORDER BY Col8) AS recID
                FROM    @Sample
            ) AS x ON x.Col7 = w.Col7
                AND x.Col8 = w.Col8
GROUP BY    w.Col7,
            w.recID - x.recID
ORDER BY    MIN(w.Col8)

Legacy Comments


Ryan Randall
2009-08-13
re: Calculating Running Streak over many records
Another idea - don't know how it compares...

--
select Col7, min(Col8) as Col8From, max(Col8) as Col8To, count(*) as Streak
from (select *, case Col7 when 1 then 1 else -1 end * (row_number() over (order by Col8) -
row_number() over (partition by Col7 order by Col8)) as p2 from @Sample) a
group by Col7, p2 order by 2
--/

Ryan Randall
2009-08-13
re: Calculating Running Streak over many records
Slightly more refined...

--
select Col7, min(Col8) as Col8From, max(Col8) as Col8To, count(*) as Streak
from (select *, (row_number() over (order by Col8) -
row_number() over (partition by Col7 order by Col8)) as p from @Sample) a
group by Col7, p order by 2
--/

Peso
2009-08-21
re: Calculating Running Streak over many records
Ryan, here is some feedback for you
http://www.sqlteam.com/forums/topic.asp?TOPIC_ID=131540

I can't see why there is a difference...

Peso
2009-08-22
re: Calculating Running Streak over many records
The difference is that in the OP sample data in the link, there are a huge amount of duplicate records. Ryan's second suggestion will handle it, while my suggestion in the blog post will not.

However, if you remove the duplicates, both mine and Ryan's suggestion will both work.

dineshrajan
2010-08-06
re: Calculating Running Streak over many records
This Query works fine. I Hope its also correct approach

DECLARE @Sample TABLE
(
id int,
Col1 INT,
Col2 INT,
Col3 INT,
Col4 INT,
Col5 INT,
Col6 INT,
Col7 INT,
Col8 int
)

INSERT @Sample
SELECT 1,43, 12345, 99887, 0, 0, 0, 0, 10 UNION ALL
SELECT 2,43, 12345, 99887, 0, 0, 0, 0, 20 UNION ALL
SELECT 3,43, 12345, 99887, 0, 0, 0, 0, 30 UNION ALL
SELECT 4,43, 12345, 99887, 0, 0, 0, 1, 40 UNION ALL
SELECT 5,43, 12345, 99887, 0, 0, 0, 1, 50 UNION ALL
SELECT 6,43, 12345, 99887, 0, 0, 0, 0, 60 UNION ALL
SELECT 7,43, 12345, 99887, 0, 0, 0, 0, 70 UNION ALL
SELECT 8,43, 12345, 99887, 0, 0, 0, 1, 80 UNION ALL
SELECT 9,43, 12345, 99887, 0, 0, 0, 0, 90




select s.*
from @Sample s
where s.col8 not in(
select s1.Col8
from @Sample s1
join
@Sample s2 on s1.id = s2.id+ 1 and s1.Col7 = s2.Col7
where s1.Col8 > s2.Col8)