sqlinfluxdb

(InfluxDB + SQL) How to count number of events in a time window using date_bin, and fill empty windows with zero?


(Using InfluxDB 3.0 cloud serverless, and SQL as the query language).

I have a simple table that captures that a named event occurred (with no data attached to it). I simply want to count the number of occurrences in a given time window. I can do that using the date_bin function. However, my problem is that if no events occurred within a certain time window, no records are present in the result set.

Instead, I want the result set to include rows for every time window in the overall time range, and show 0 if no events occurred within it.

Here's my current query:

SELECT date_bin('1 minute', time) AS time, Count("Event")
FROM "CW" 
WHERE $__timeFilter(time) 
AND "Event" = 'thing_xyz_happened'
GROUP BY 1
ORDER BY "time"

So for example, consider my overall query time range being 5 minutes. In the first minute, 1 "thing_xyz_happened" event occurred, and in the second minute, it happened twice. In minutes 3, 4 and 5, no such event happened and therefore no records exist in the database for those minutes. Currently here is what that query returns:

Time Count
2024-06-03 13:37 1
2024-06-03 13:38 2

Note that 13:39, :40 and :41 are absent. This messes up my bar chart graphs. I want to show an actual "0" for those last 3 minutes:

Time Count
2024-06-03 13:37 1
2024-06-03 13:38 2
2024-06-03 13:39 0
2024-06-03 13:40 0
2024-06-03 13:41 0

I've looked at date_bin_gapfill, but the only options available are interpolation or carrying-forward of previous data. Neither of those will give me the 0 I want.


Solution

  • try with generate_series function:

    WITH time_series AS (
      SELECT generate_series(start_time, end_time, 1m) AS time
      FROM (
        SELECT date_trunc('minute', $__timeFrom()) AS start_time,
               date_trunc('minute', $__timeTo()) AS end_time
      )
    )
    SELECT date_bin('1 minute', ts.time) AS time,
           COUNT("Event") AS count
    FROM time_series ts
    LEFT JOIN "CW" c ON date_bin('1 minute', c.time) = date_bin('1 minute', ts.time) AND c."Event" = 'thing_xyz_happened'
    GROUP BY 1
    ORDER BY time;