- SQL issue - calculate max days sequence
- uid (INT) | created_at (DATETIME)
- SELECT DISTINCT DATE(created_at) AS d FROM visits WHERE uid = 123
- d
- ------------
- 2012-04-28
- 2012-04-29
- 2012-04-30
- 2012-05-03
- 2012-05-04
- -- returns starts of the vitit series
- SELECT t1.d as s FROM testing t1
- LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', -1, t1.d))
- WHERE t2.d is null GROUP BY t1.d
- s
- ---------------------
- 2012-04-28 01:00:00
- 2012-05-03 01:00:00
- -- returns end of the vitit series
- SELECT t1.d as f FROM testing t1
- LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', 1, t1.d))
- WHERE t2.d is null GROUP BY t1.d
- f
- ---------------------
- 2012-04-30 01:00:00
- 2012-05-04 01:00:00
- SELECT s, f, DATEDIFF(day, s, f) + 1 as seq FROM (
- SELECT t1.d as s, ROW_NUMBER() OVER () as o1 FROM testing t1
- LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', -1, t1.d))
- WHERE t2.d is null GROUP BY t1.d
- ) tbl1 LEFT JOIN (
- SELECT t1.d as f, ROW_NUMBER() OVER () as o2 FROM testing t1
- LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', 1, t1.d))
- WHERE t2.d is null GROUP BY t1.d
- ) tbl2 ON o1 = o2
- s | f | seq
- ---------------------+---------------------+-----
- 2012-04-28 01:00:00 | 2012-04-30 01:00:00 | 3
- 2012-05-03 01:00:00 | 2012-05-04 01:00:00 | 2
- with grouped_result as
- (
- select
- sr.d,
- sum((fr.d is null)::int) over(order by sr.d) as group_number
- from tbl sr
- left join tbl fr on sr.d = fr.d + interval '1 day'
- )
- select d, group_number, count(d) over m as consecutive_days
- from grouped_result
- window m as (partition by group_number)
- d | group_number | consecutive_days
- ---------------------+--------------+------------------
- 2012-04-28 08:00:00 | 1 | 3
- 2012-04-29 08:00:00 | 1 | 3
- 2012-04-30 08:00:00 | 1 | 3
- 2012-05-03 08:00:00 | 2 | 2
- 2012-05-04 08:00:00 | 2 | 2
- (5 rows)
- with grouped_result as
- (
- select
- sr.d,
- sum((fr.d is null)::int) over(order by sr.d) as group_number
- from tbl sr
- left join tbl fr on sr.d = fr.d + interval '1 day'
- )
- select min(d) as starting_date, max(d) as end_date, count(d) as consecutive_days
- from grouped_result
- group by group_number
- -- order by consecutive_days desc limit 1
- STARTING_DATE END_DATE CONSECUTIVE_DAYS
- April, 28 2012 08:00:00-0700 April, 30 2012 08:00:00-0700 3
- May, 03 2012 08:00:00-0700 May, 04 2012 08:00:00-0700 2
- with headers as
- (
- select
- d,lag(d) over m is null or d - lag(d) over m <> interval '1 day' as header
- from tbl
- window m as (order by d)
- )
- ,sequence_group as
- (
- select d, sum(header::int) over (order by d) as group_number
- from headers
- )
- select min(d) as starting_date,max(d) as ending_date,count(d) as consecutive_days
- from sequence_group
- group by group_number
- -- order by consecutive_days desc limit 1
- SET @nextDate = CURRENT_DATE;
- SET @RowNum = 1;
- SELECT MAX(RowNumber) AS ConecutiveVisits
- FROM ( SELECT @RowNum := IF(@NextDate = Created_At, @RowNum + 1, 1) AS RowNumber,
- Created_At,
- @NextDate := DATE_ADD(Created_At, INTERVAL 1 DAY) AS NextDate
- FROM Visits
- ORDER BY Created_At
- ) Visits
- ;WITH RECURSIVE VisitsCTE AS
- ( SELECT Created_At, 1 AS ConsecutiveDays
- FROM Visits
- UNION ALL
- SELECT v.Created_At, ConsecutiveDays + 1
- FROM Visits v
- INNER JOIN VisitsCTE cte
- ON 1 + cte.Created_At = v.Created_At
- )
- SELECT MAX(ConsecutiveDays) AS ConsecutiveDays
- FROM VisitsCTE
- create table #tempdates (
- mydate date
- )
- insert into #tempdates(mydate) values('2012-04-28')
- insert into #tempdates(mydate) values('2012-04-29')
- insert into #tempdates(mydate) values('2012-04-30')
- insert into #tempdates(mydate) values('2012-05-03')
- insert into #tempdates(mydate) values('2012-05-04');
- with maxdays (s, e, c)
- as
- (
- select mydate, mydate, 1
- from #tempdates
- union all
- select m.s, mydate, m.c + 1
- from #tempdates t
- inner join maxdays m on DATEADD(day, -1, t.mydate)=m.e
- )
- select MIN(o.s),o.e,max(o.c)
- from (
- select m1.s,max(m1.e) e,max(m1.c) c
- from maxdays m1
- group by m1.s
- ) o
- group by o.e
- drop table #tempdates
- ;WITH
- visit_dates (
- visit_id,
- date_id,
- group_id
- )
- AS
- (
- SELECT
- ROW_NUMBER() OVER (ORDER BY TRUNC(created_at)),
- TRUNC(SYSDATE) - TRUNC(created_at),
- TRUNC(SYSDATE) - TRUNC(created_at) - ROW_NUMBER() OVER (ORDER BY TRUNC(created_at))
- FROM
- visits
- GROUP BY
- TRUNC(created_at)
- )
- ,
- group_duration (
- group_id,
- duration
- )
- AS
- (
- SELECT
- group_id,
- MAX(date_id) - MIN(date_id) + 1 AS duration
- FROM
- visit_dates
- GROUP BY
- group_id
- )
- SELECT
- MAX(duration) AS max_duration
- FROM
- group_duration
- with headers as
- (
- select
- d,
- lag(d) over m is null or d - lag(d) over m <> interval '1 day' as header
- from tbl
- window m as (order by d)
- )
- ,sequence_group as
- (
- select d, sum(header::int) over m as group_number
- from headers
- window m as (order by d)
- )
- ,consecutive_list as
- (
- select d, group_number, count(d) over m as consecutive_count
- from sequence_group
- window m as (partition by group_number)
- )
- select * from consecutive_list
- with headers as
- (
- select
- d,
- lag(d) over m is null or d - lag(d) over m <> interval '1 day' as header
- from tbl
- window m as (order by d)
- )
- select * from headers
- d | header
- ---------------------+--------
- 2012-04-28 08:00:00 | t
- 2012-04-29 08:00:00 | f
- 2012-04-30 08:00:00 | f
- 2012-05-03 08:00:00 | t
- 2012-05-04 08:00:00 | f
- (5 rows)
- with headers as
- (
- select
- d,
- lag(d) over m is null or d - lag(d) over m <> interval '1 day' as header
- from tbl
- window m as (order by d)
- )
- ,sequence_group as
- (
- select d, sum(header::int) over m as group_number
- from headers
- window m as (order by d)
- )
- select * from sequence_group
- d | group_number
- ---------------------+--------------
- 2012-04-28 08:00:00 | 1
- 2012-04-29 08:00:00 | 1
- 2012-04-30 08:00:00 | 1
- 2012-05-03 08:00:00 | 2
- 2012-05-04 08:00:00 | 2
- (5 rows)
- with headers as
- (
- select
- d,
- lag(d) over m is null or d - lag(d) over m <> interval '1 day' as header
- from tbl
- window m as (order by d)
- )
- ,sequence_group as
- (
- select d, sum(header::int) over m as group_number
- from headers
- window m as (order by d)
- )
- ,consecutive_list as
- (
- select d, group_number, count(d) over m as consecutive_count
- from sequence_group
- window m as (partition by group_number)
- )
- select * from consecutive_list
- d | group_number | consecutive_count
- ---------------------+--------------+-----------------
- 2012-04-28 08:00:00 | 1 | 3
- 2012-04-29 08:00:00 | 1 | 3
- 2012-04-30 08:00:00 | 1 | 3
- 2012-05-03 08:00:00 | 2 | 2
- 2012-05-04 08:00:00 | 2 | 2
- (5 rows)
- select
- min(d) as starting_date, max(d) as ending_date,
- count(d) as consecutive_days
- from
- (
- select
- sr.d,
- IF(fr.d is null,@group_number := @group_number + 1,@group_number)
- as group_number
- from tbl sr
- left join tbl fr on sr.d = adddate(fr.d,interval 1 day)
- cross join (select @group_number := 0) as grp
- ) as x
- group by group_number
- STARTING_DATE ENDING_DATE CONSECUTIVE_DAYS
- April, 28 2012 08:00:00-0700 April, 30 2012 08:00:00-0700 3
- May, 03 2012 08:00:00-0700 May, 04 2012 08:00:00-0700 2
- WITH x AS (
- SELECT created_at AS d
- , lag(created_at) OVER (ORDER BY created_at) = (created_at - 1) AS nu
- FROM visits
- WHERE uid = 1
- )
- , y AS (
- SELECT d, count(NULLIF(nu, TRUE)) OVER (ORDER BY d) AS seq
- FROM x
- )
- SELECT count(*) AS max_days, min(d) AS seq_from, max(d) AS seq_to
- FROM y
- GROUP BY seq
- ORDER BY 1 DESC
- LIMIT 1;
- max_days | seq_from | seq_to
- ---------+------------+-----------
- 3 | 2012-04-28 | 2012-04-30
- select uid, min(d) as startdate, count(*) as numdaysinseq
- from (select uid, d, adddate(d, interval -offset day) as groupstart
- from (select uid, d, row_number() over (partition by uid order by date) as offset
- from (SELECT DISTINCT uid, DATE(created_at) AS d
- FROM visits
- ) t
- ) t
- ) t
- select
- min(gr.d) as start_date,
- max(gr.d) as end_date,
- date_part('day', max(gr.d) - min(gr.d))+1 as consecutive_days
- from
- (
- select
- cr.d, (row_number() over() - 1) / 2 as pair_number
- from tbl cr
- left join tbl pr on pr.d = cr.d - interval '1 day'
- left join tbl nr on nr.d = cr.d + interval '1 day'
- where pr.d is null <> nr.d is null
- ) as gr
- group by pair_number
- order by start_date
- (row_number() over() - 1) / 2 as pair_number
- select
- min(gr.d) as start_date,
- max(gr.d) as end_date,
- datediff(day, min(gr.d),max(gr.d)) +1 as consecutive_days
- from
- (
- select
- cr.d, (row_number() over(order by cr.d) - 1) / 2 as pair_number
- from tbl cr
- left join tbl pr on pr.d = dateadd(day,-1,cr.d)
- left join tbl nr on nr.d = dateadd(day,+1,cr.d)
- where
- case when pr.d is null then 1 else 0 end
- <> case when nr.d is null then 1 else 0 end
- ) as gr
- group by pair_number
- order by start_date
- pr.d is null <> nr.d is null
- case when pr.d is null then 1 else 0 end
- <> case when nr.d is null then 1 else 0 end