Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Grouping data by time interval

I want to group the data in a table by time interval. The table keeps the order info that includes the userid, item name, model, quantity, activity date, etc. Now I want to group this data by time intervals. The time interval could be anything like 5 min, 10 min, 15, etc. Also, the query should return only those users (all the column data) who made orders more than once within that 5 minutes interval. Is it possible to achieve this in one SQL query? I use Oracle.

Thank you

Edit:

Sample data

**userid    item name    model      quantity   order date**
abc calculator   cdm83ss    1      02-FEB-2013 09:20:13     
abc alarm clock  actp001    1      02-FEB-2013 09:26:22
yyy iPhone       iP4    1      02-FEB-2013 09:28:14
abc alarm clock  actz321    2      02-FEB-2013 09:30:00
zzz backpack     bp344tk    1      04-FEB-2013 13:15:00
zzz backpack     bp234zz    2      04-FEB-2013 13:19:32
zzz camera       cm234  1      04-FEB-2013 13:20:22 
ttt tv       fs45yup    1      04-FEB-2013 13:28:19

I expect to get:

**userid    item name    model      quantity   order date**
abc         calculator   cdm83ss    1      02-FEB-2013 09:20:13     
abc         alarm clock  actp001    1      02-FEB-2013 09:26:22
abc         alarm clock  actz321    2      02-FEB-2013 09:30:00
zzz         backpack     bp344tk    1      04-FEB-2013 13:15:00
zzz         backpack     bp234zz    2      04-FEB-2013 13:19:32
zzz         camera       cm234  1      04-FEB-2013 13:20:22 
like image 754
Mike Avatar asked Feb 08 '13 20:02

Mike


2 Answers

Yes. Presumably you want to see the result as a datetime value as well. This requires some datetime arithmetic. Basically, getting the number of minutes since midnight, dividing by the number of minutes and then multiplying again (to round down). Then adding back in the time at midnight:

select t.*
from (select t.*,
             count(*) over (partition by userid, interval) as CntInInterval
      from (select trunc(orderdate)+
                   (floor(((orderdate - trunc(orderdate))*24*60)/10)*10)/(24*60) as interval, t.*
            from t
           ) t
     ) t
where cntInInterval > 1

To group by time intervals, you would use:

      select interval, count(*)
      from (select trunc(orderdate)+floor(((orderdate - trunc(orderdate))*24*60)/10)*10 as interval, t.*
            from t
           ) t
      group by interval

In these queries, "10" stands for any number of minutes. Note that these are calculated since midnight, so a value like 17 always starts with the first 17 minutes of the day.

The definition of interval is an arithmetic expression on dates.

          trunc(orderdate)+floor(((orderdate - trunc(orderdate))*24*60)/10)*10 as interval,

The first part, trunc(orderdate), is Oracle syntax for removing the time part of a date. This moves the date to midnight at the beginning of the day.

The expression orderdate - trunc(orderdate) calculates the number of days since midnight -- this is a fractional part of one day. So, 0.25 would be 6:00 a.m. The *24*60 converts this to minutes. So, 0.25 becomes 0.25*60*24 = 360 -- the number of minutes since midnight.

Then the expression floor(x/y)*y simply "truncates" any value to the lower multiple of y. So, floor(118/10) is 11, and 11*10 is 110. In other words, this will map all values between a*y and (a+1)*y (up to not including) to the same value, a*y.

Consider the expression in practice, on 6:08 a.m. on 2013-01-01:

`trunc(orderdate)` moves the date to midnight on 2013-01-01.
`orderdate - trunc(orderdate)` creates a number like 0.25.
`((orderdate - trunc(orderdate))*24*60)` produces the value 368
`floor(((orderdate - trunc(orderdate))*24*60)/10)*10` produces 360
`floor(((orderdate - trunc(orderdate))*24*60)/10)*10*(1/24*60)` produces 0.25

And when this is added to minight, the time turns into 6:00 a.m. again.

like image 94
Gordon Linoff Avatar answered Nov 12 '22 08:11

Gordon Linoff


In case you need simpler way to get time interval - I cannot help you with anything else as i do not know your tables and data:

-- Time interval - every 15 min from midnight --
SELECT To_Char(trunc(SYSDATE) + (LEVEL/1440*15), 'HH24:MI') interval_15_min 
  FROM dual
CONNECT BY LEVEL <= 10 -- this is orbitraty 
/
SQL>

INTERVAL_15_MIN
--------------
00:15
00:30
00:45
...
like image 3
Art Avatar answered Nov 12 '22 06:11

Art