Don't like ads? PRO users don't see any ads ;-)
Guest

Untitled

By: a guest on Jul 29th, 2012  |  syntax: None  |  size: 9.61 KB  |  hits: 14  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. SQL issue - calculate max days sequence
  2. uid (INT) | created_at (DATETIME)
  3.        
  4. SELECT DISTINCT DATE(created_at) AS d FROM visits WHERE uid = 123
  5.        
  6. d      
  7. ------------
  8.  2012-04-28
  9.  2012-04-29
  10.  2012-04-30
  11.  2012-05-03
  12.  2012-05-04
  13.        
  14. -- returns starts of the vitit series
  15. SELECT t1.d as s FROM testing t1
  16. LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', -1, t1.d))
  17. WHERE t2.d is null GROUP BY t1.d
  18.  
  19.           s          
  20. ---------------------
  21.  2012-04-28 01:00:00
  22.  2012-05-03 01:00:00
  23.  
  24. -- returns end of the vitit series
  25. SELECT t1.d as f FROM testing t1
  26. LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', 1, t1.d))
  27. WHERE t2.d is null GROUP BY t1.d
  28.  
  29.           f          
  30. ---------------------
  31.  2012-04-30 01:00:00
  32.  2012-05-04 01:00:00
  33.        
  34. SELECT s, f, DATEDIFF(day, s, f) + 1 as seq FROM (
  35.     SELECT t1.d as s, ROW_NUMBER() OVER () as o1 FROM testing t1
  36.     LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', -1, t1.d))
  37.     WHERE t2.d is null GROUP BY t1.d
  38. ) tbl1 LEFT JOIN (
  39.     SELECT t1.d as f, ROW_NUMBER() OVER () as o2 FROM testing t1
  40.     LEFT JOIN testing t2 ON DATE(t2.d) = DATE(TIMESTAMPADD('day', 1, t1.d))
  41.     WHERE t2.d is null GROUP BY t1.d
  42. ) tbl2 ON o1 = o2
  43.        
  44. s          |          f          | seq
  45. ---------------------+---------------------+-----
  46.  2012-04-28 01:00:00 | 2012-04-30 01:00:00 |   3
  47.  2012-05-03 01:00:00 | 2012-05-04 01:00:00 |   2
  48.        
  49. with grouped_result as
  50. (
  51.     select
  52.        sr.d,
  53.        sum((fr.d is null)::int) over(order by sr.d) as group_number
  54.     from tbl sr
  55.     left join tbl fr on sr.d = fr.d + interval '1 day'
  56. )
  57. select d, group_number, count(d) over m as consecutive_days
  58. from grouped_result
  59. window m as (partition by group_number)
  60.        
  61. d          | group_number | consecutive_days
  62. ---------------------+--------------+------------------
  63.  2012-04-28 08:00:00 |            1 |                3
  64.  2012-04-29 08:00:00 |            1 |                3
  65.  2012-04-30 08:00:00 |            1 |                3
  66.  2012-05-03 08:00:00 |            2 |                2
  67.  2012-05-04 08:00:00 |            2 |                2
  68. (5 rows)
  69.        
  70. with grouped_result as
  71. (
  72.     select
  73.        sr.d,
  74.        sum((fr.d is null)::int) over(order by sr.d) as group_number
  75.     from tbl sr
  76.     left join tbl fr on sr.d = fr.d + interval '1 day'
  77. )
  78. select min(d) as starting_date, max(d) as end_date, count(d) as consecutive_days
  79. from grouped_result
  80. group by group_number
  81. -- order by consecutive_days desc limit 1
  82.  
  83.  
  84. STARTING_DATE                END_DATE                     CONSECUTIVE_DAYS
  85. April, 28 2012 08:00:00-0700 April, 30 2012 08:00:00-0700 3
  86. May, 03 2012 08:00:00-0700   May, 04 2012 08:00:00-0700   2
  87.        
  88. with headers as
  89. (
  90.     select
  91.       d,lag(d) over m is null or d - lag(d) over m  <> interval '1 day' as header
  92.     from tbl
  93.     window m as (order by d)
  94. )      
  95. ,sequence_group as
  96. (
  97.     select d, sum(header::int) over (order by d) as group_number
  98.     from headers  
  99. )
  100. select min(d) as starting_date,max(d) as ending_date,count(d) as consecutive_days
  101. from sequence_group
  102. group by group_number
  103. -- order by consecutive_days desc limit 1
  104.        
  105. SET @nextDate = CURRENT_DATE;
  106. SET @RowNum = 1;
  107.  
  108. SELECT MAX(RowNumber) AS ConecutiveVisits
  109. FROM    (   SELECT  @RowNum := IF(@NextDate = Created_At, @RowNum + 1, 1) AS RowNumber,
  110.                     Created_At,
  111.                     @NextDate := DATE_ADD(Created_At, INTERVAL 1 DAY) AS NextDate
  112.             FROM    Visits
  113.             ORDER BY Created_At
  114.         ) Visits
  115.        
  116. ;WITH RECURSIVE VisitsCTE AS
  117.  (  SELECT  Created_At, 1 AS ConsecutiveDays
  118.     FROM    Visits
  119.     UNION ALL
  120.     SELECT  v.Created_At, ConsecutiveDays + 1
  121.     FROM    Visits v
  122.             INNER JOIN VisitsCTE cte
  123.                 ON 1 + cte.Created_At = v.Created_At
  124. )
  125. SELECT  MAX(ConsecutiveDays) AS ConsecutiveDays
  126. FROM    VisitsCTE
  127.        
  128. create table #tempdates (
  129.     mydate date
  130. )
  131.  
  132. insert into #tempdates(mydate) values('2012-04-28')
  133. insert into #tempdates(mydate) values('2012-04-29')
  134. insert into #tempdates(mydate) values('2012-04-30')
  135. insert into #tempdates(mydate) values('2012-05-03')
  136. insert into #tempdates(mydate) values('2012-05-04');
  137.  
  138. with maxdays (s, e, c)
  139. as
  140. (
  141.     select mydate, mydate, 1
  142.     from #tempdates
  143.     union all
  144.     select m.s, mydate, m.c + 1
  145.     from #tempdates t
  146.     inner join maxdays m on DATEADD(day, -1, t.mydate)=m.e
  147. )
  148. select MIN(o.s),o.e,max(o.c)
  149. from (
  150.   select m1.s,max(m1.e) e,max(m1.c) c
  151.   from maxdays m1
  152.   group by m1.s
  153. ) o
  154. group by o.e
  155.  
  156. drop table #tempdates
  157.        
  158. ;WITH
  159.   visit_dates (
  160.     visit_id,
  161.     date_id,
  162.     group_id
  163.   )
  164. AS
  165. (
  166.   SELECT
  167.     ROW_NUMBER() OVER (ORDER BY TRUNC(created_at)),
  168.     TRUNC(SYSDATE) - TRUNC(created_at),
  169.     TRUNC(SYSDATE) - TRUNC(created_at) - ROW_NUMBER() OVER (ORDER BY TRUNC(created_at))
  170.   FROM
  171.     visits
  172.   GROUP BY
  173.     TRUNC(created_at)
  174. )
  175. ,
  176.   group_duration (
  177.     group_id,
  178.     duration
  179.   )
  180. AS
  181. (
  182.   SELECT
  183.     group_id,
  184.     MAX(date_id) - MIN(date_id) + 1  AS duration
  185.   FROM
  186.     visit_dates
  187.   GROUP BY
  188.     group_id
  189. )
  190. SELECT
  191.   MAX(duration)  AS max_duration
  192. FROM
  193.   group_duration
  194.        
  195. with headers as
  196. (
  197.     select
  198.         d,
  199.         lag(d) over m is null or d - lag(d) over m  <> interval '1 day' as header
  200.  
  201.     from tbl
  202.     window m as (order by d)
  203. )      
  204. ,sequence_group as
  205. (
  206.     select d, sum(header::int) over m as group_number
  207.     from headers
  208.     window m as (order by d)
  209. )
  210. ,consecutive_list as
  211. (
  212.     select d, group_number, count(d) over m as consecutive_count
  213.     from sequence_group
  214.     window m as (partition by group_number)
  215. )
  216. select * from consecutive_list
  217.        
  218. with headers as
  219. (
  220.     select
  221.         d,
  222.         lag(d) over m is null or d - lag(d) over m  <> interval '1 day' as header
  223.  
  224.     from tbl
  225.     window m as (order by d)
  226. )
  227. select * from headers
  228.        
  229. d          | header
  230. ---------------------+--------
  231.  2012-04-28 08:00:00 | t
  232.  2012-04-29 08:00:00 | f
  233.  2012-04-30 08:00:00 | f
  234.  2012-05-03 08:00:00 | t
  235.  2012-05-04 08:00:00 | f
  236. (5 rows)
  237.        
  238. with headers as
  239. (
  240.     select
  241.         d,
  242.         lag(d) over m is null or d - lag(d) over m  <> interval '1 day' as header
  243.  
  244.     from tbl
  245.     window m as (order by d)
  246. )      
  247. ,sequence_group as
  248. (
  249.     select d, sum(header::int) over m as group_number
  250.     from headers
  251.     window m as (order by d)
  252. )
  253. select * from sequence_group
  254.        
  255. d          | group_number
  256. ---------------------+--------------
  257.  2012-04-28 08:00:00 |            1
  258.  2012-04-29 08:00:00 |            1
  259.  2012-04-30 08:00:00 |            1
  260.  2012-05-03 08:00:00 |            2
  261.  2012-05-04 08:00:00 |            2
  262. (5 rows)
  263.        
  264. with headers as
  265. (
  266.     select
  267.         d,
  268.         lag(d) over m is null or d - lag(d) over m  <> interval '1 day' as header
  269.  
  270.     from tbl
  271.     window m as (order by d)
  272. )      
  273. ,sequence_group as
  274. (
  275.     select d, sum(header::int) over m as group_number
  276.     from headers
  277.     window m as (order by d)
  278. )
  279. ,consecutive_list as
  280. (
  281. select d, group_number, count(d) over m as consecutive_count
  282. from sequence_group
  283. window m as (partition by group_number)
  284. )
  285. select * from consecutive_list
  286.        
  287. d          | group_number | consecutive_count
  288. ---------------------+--------------+-----------------
  289.  2012-04-28 08:00:00 |            1 |               3
  290.  2012-04-29 08:00:00 |            1 |               3
  291.  2012-04-30 08:00:00 |            1 |               3
  292.  2012-05-03 08:00:00 |            2 |               2
  293.  2012-05-04 08:00:00 |            2 |               2
  294. (5 rows)
  295.        
  296. select
  297.    min(d) as starting_date, max(d) as ending_date,
  298.    count(d) as consecutive_days
  299. from
  300. (
  301.   select
  302.      sr.d,
  303.      IF(fr.d is null,@group_number := @group_number + 1,@group_number)
  304.         as group_number
  305.   from tbl sr
  306.   left join tbl fr on sr.d = adddate(fr.d,interval 1 day)
  307.   cross join (select @group_number := 0) as grp
  308. ) as x
  309. group by group_number
  310.        
  311. STARTING_DATE                  ENDING_DATE                  CONSECUTIVE_DAYS
  312. April, 28 2012 08:00:00-0700   April, 30 2012 08:00:00-0700 3
  313. May, 03 2012 08:00:00-0700     May, 04 2012 08:00:00-0700   2
  314.        
  315. WITH x AS (
  316.     SELECT created_at AS d
  317.          , lag(created_at) OVER (ORDER BY created_at) = (created_at - 1) AS nu
  318.     FROM   visits
  319.     WHERE  uid = 1
  320.     )
  321.    , y AS (
  322.     SELECT d, count(NULLIF(nu, TRUE)) OVER (ORDER BY d) AS seq
  323.     FROM   x
  324.     )
  325. SELECT count(*) AS max_days, min(d) AS seq_from,  max(d) AS seq_to
  326. FROM   y
  327. GROUP  BY seq
  328. ORDER  BY 1 DESC
  329. LIMIT  1;
  330.        
  331. max_days | seq_from   | seq_to
  332. ---------+------------+-----------
  333. 3        | 2012-04-28 | 2012-04-30
  334.        
  335. select uid, min(d) as startdate, count(*) as numdaysinseq
  336. from (select uid, d, adddate(d, interval -offset day) as groupstart
  337.       from (select uid, d, row_number() over (partition by uid order by date) as offset
  338.             from (SELECT DISTINCT uid, DATE(created_at) AS d
  339.                   FROM visits
  340.                  ) t
  341.            ) t
  342.      ) t
  343.        
  344. select
  345.   min(gr.d) as start_date,
  346.   max(gr.d) as end_date,
  347.   date_part('day', max(gr.d) - min(gr.d))+1 as consecutive_days
  348. from
  349. (
  350.   select
  351.   cr.d, (row_number() over() - 1) / 2 as pair_number
  352.   from tbl cr  
  353.   left join tbl pr on pr.d = cr.d - interval '1 day'
  354.   left join tbl nr on nr.d = cr.d + interval '1 day'
  355.   where pr.d is null <> nr.d is null
  356. ) as gr
  357. group by pair_number
  358. order by start_date
  359.        
  360. (row_number() over() - 1) / 2 as pair_number
  361.        
  362. select
  363.   min(gr.d) as start_date,
  364.   max(gr.d) as end_date,
  365.   datediff(day, min(gr.d),max(gr.d)) +1 as consecutive_days
  366. from
  367. (
  368.   select
  369.      cr.d, (row_number() over(order by cr.d) - 1) / 2 as pair_number
  370.   from tbl cr  
  371.   left join tbl pr on pr.d = dateadd(day,-1,cr.d)
  372.   left join tbl nr on nr.d = dateadd(day,+1,cr.d)
  373.   where        
  374.        case when pr.d is null then 1 else 0 end
  375.     <> case when nr.d is null then 1 else 0 end
  376. ) as gr
  377. group by pair_number
  378. order by start_date
  379.        
  380. pr.d is null <> nr.d is null
  381.        
  382. case when pr.d is null then 1 else 0 end
  383. <> case when nr.d is null then 1 else 0 end