Search code examples
sqliteandroid-sqlite

SQLite: Group data within certain time interval


I have a single table which stores data of orders:

Orders Table:

id | order_time          | quantity | ...
1  | 1592821854318       | 2
2  | 1592901538199       | 4
3  | 1592966454547       | 1
4  | 1593081282406       | 9
5  | 1593141826330       | 6

order_time table is UNIX timestamp.

Using below query I am able to get available data grouped by days (86400000 = 24 hours):

 SELECT order_time+ (86400000 - (order_time % 86400000)) as gap, SUM(quantity) as 
            totalOrdersBetweenInterval
    FROM USAGE_DETAILS ud 
                WHERE order_time >= 1590969600 AND order_time <= 1593388799000 
          
GROUP BY gap 
ORDER BY gap ASC

Suppose for this month of June, I receive order on 1, 4, 6, 7 date then by using above query I am able to retrieve data as follow :

gap | totalOrdersBetweenInterval 
1   | 5
4   | 6
6   | 4
7   | 10

I would receive UNIX timestamp in gap column but for the sake of example I have used readable dates.

Above query will only retrieve data for the days which would have received order but I want to split data in range like below which also include days with no orders :

gap | totalOrdersBetweenInterval 
1   | 5
2   | 0
3   | 0
4   | 6
5   | 0
6   | 4
7   | 10
8   | 0
9   | 0
.   | .
.   | .

How do I go about that?


Solution

  • You need a query that returns 30 rows:1,2,...,30 for the days of June.
    You could do it with a recursive CTE:

    with days as (
      select 1 day
      union all
      select day + 1
      from days
      where day < 30
    )
    

    but I'm not sure if Android uses a version of SQLite that supports CTEs.

    If it does support them, all you need to do is join the CTE with a LEFT join to your query:

    with 
      days as (
        select 1 day
        union all
        select day + 1
        from days
        where day < 30
      ),
      yourquery as (
        <your query here>
      )
    select d.day, coalesce(t.totalOrdersBetweenInterval, 0) totalOrdersBetweenInterval
    from days d left join yourquery t
    on t.gap = d.day
    

    If Android does not support CTEs you will have to build the query that returns the days with UNION ALL:

    select d.day, coalesce(t.totalOrdersBetweenInterval, 0) totalOrdersBetweenInterval
    from (
      select 1 day union all select 2 union all
      select 3 union all select 4 union all
      ......................................
      select 29 union all select 30
    ) d left join (
      <your query here>
    ) t
    on t.gap = d.day