Continuous Queries

This is archived documentation for InfluxData product versions that are no longer maintained. For newer documentation, see the latest InfluxData documentation.

Introduction

Continuous Queries (CQ) are InfluxQL queries that run automatically and periodically on realtime data and store query results in a specified measurement.

Basic SyntaxAdvanced SyntaxCQ Management
Examples of Basic SyntaxExamples of Advanced SyntaxCQ Use Cases
Common Issues with Basic SyntaxCommon Issues with Advanced SyntaxFurther Reading

Syntax

Basic Syntax

CREATE CONTINUOUS QUERY <cq_name> ON <database_name>
BEGIN
  <cq_query>
END

Description of Basic Syntax

The cq_query


The cq_query requires a function, an INTO clause, and a GROUP BY time() clause:

SELECT <function[s]> INTO <destination_measurement> FROM <measurement> [WHERE <stuff>] GROUP BY time(<interval>)[,<tag_key[s]>]

Note: Notice that the cq_query does not require a time range in a WHERE clause. InfluxDB automatically generates a time range for the cq_query when it executes the CQ. Any user-specified time ranges in the cq_query’s WHERE clause will be ignored by the system.

Schedule and Coverage


CQs operate on realtime data. They use the local server’s timestamp, the GROUP BY time() interval, and InfluxDB’s preset time boundaries to determine when to execute and what time range to cover in the query.

CQs execute at the same interval as the cq_query’s GROUP BY time() interval, and they run at the start of InfluxDB’s preset time boundaries. If the GROUP BY time() interval is one hour, the CQ executes at the start of every hour.

When the CQ executes, it runs a single query for the time range between now() and now() minus the GROUP BY time() interval. If the GROUP BY time() interval is one hour and the current time is 17:00, the query’s time range is between 16:00 and 16:59.

Examples of Basic Syntax

The examples below use the following sample data in the transportation database. The measurement bus_data stores 15-minute resolution data on the number of bus passengers and complaints:

name: bus_data
--------------
time                   passengers   complaints
2016-08-28T07:00:00Z   5            9
2016-08-28T07:15:00Z   8            9
2016-08-28T07:30:00Z   8            9
2016-08-28T07:45:00Z   7            9
2016-08-28T08:00:00Z   8            9
2016-08-28T08:15:00Z   15           7
2016-08-28T08:30:00Z   15           7
2016-08-28T08:45:00Z   17           7
2016-08-28T09:00:00Z   20           7
Example 1: Automatically downsample data


Use a simple CQ to automatically downsample data from a single field and write the results to another measurement in the same database.

CREATE CONTINUOUS QUERY "cq_basic" ON "transportation"
BEGIN
  SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h)
END

cq_basic calculates the average hourly number of passengers from the bus_data measurement and stores the results in the average_passengers measurement in the transportation database.

cq_basic executes at one-hour intervals, the same interval as the GROUP BY time() interval. Every hour, cq_basic runs a single query that covers the time range between now() and now() minus the GROUP BY time() interval, that is, the time range between now() and one hour prior to now().

Annotated log output on the morning of August 28, 2016:

At 8:00 cq_basic executes a query with the time range time >= '7:00' AND time < '08:00'.
cq_basic writes one point to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   7

At 9:00 cq_basic executes a query with the time range time >= '8:00' AND time < '9:00'.
cq_basic writes one point to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T08:00:00Z   13.75

Results:

> SELECT * FROM "average_passengers"
name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   7
2016-08-28T08:00:00Z   13.75
Example 2: Automatically downsample data into another retention policy


Fully qualify the destination measurement to store the downsampled data in a non-DEFAULT retention policy (RP).

CREATE CONTINUOUS QUERY "cq_basic_rp" ON "transportation"
BEGIN
  SELECT mean("passengers") INTO "transportation"."three_weeks"."average_passengers" FROM "bus_data" GROUP BY time(1h)
END

cq_basic_rp calculates the average hourly number of passengers from the bus_data measurement and stores the results in the transportation database, the three_weeks RP, and the average_passengers measurement.

cq_basic_rp executes at one-hour intervals, the same interval as the GROUP BY time() interval. Every hour, cq_basic_rp runs a single query that covers the time range between now() and now() minus the GROUP BY time() interval, that is, the time range between now() and one hour prior to now().

Annotated log output on the morning of August 28, 2016:

At 8:00 cq_basic_rp executes a query with the time range time >= '7:00' AND time < '8:00'.
cq_basic_rp writes one point to the three_weeks RP and the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   7

At 9:00 cq_basic_rp executes a query with the time range time >= '8:00' AND time < '9:00'.
cq_basic_rp writes one point to the three_weeks RP and the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T08:00:00Z   13.75

Results:

> SELECT * FROM "transportation"."three_weeks"."average_passengers"
name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   7
2016-08-28T08:00:00Z   13.75

cq_basic_rp uses CQs and retention policies to automatically downsample data and keep those downsampled data for an alternative length of time. See the Downsampling and Data Retention guide for an in-depth discussion about this CQ use case.

Example 3: Automatically downsample a database with backreferencing


Use a function with a wildcard (*) and INTO query’s backreferencing syntax to automatically downsample data from all measurements and numerical fields in a database.

CREATE CONTINUOUS QUERY "cq_basic_br" ON "transportation"
BEGIN
  SELECT mean(*) INTO "downsampled_transportation"."autogen".:MEASUREMENT FROM /.*/ GROUP BY time(30m),*
END

cq_basic_br calculates the 30-minute average of passengers and complaints from every measurement in the transportation database (in this case, there’s only the bus_data measurement). It stores the results in the downsampled_transportation database.

cq_basic_br executes at 30 minutes intervals, the same interval as the GROUP BY time() interval. Every 30 minutes, cq_basic_br runs a single query that covers the time range between now() and now() minus the GROUP BY time() interval, that is, the time range between now() and 30 minutes prior to now().

Annotated log output on the morning of August 28, 2016:

At 7:30, cq_basic_br executes a query with the time range time >= '7:00' AND time < '7:30'. cq_basic_br writes two points to the bus_data measurement in the downsampled_transportation database:

name: bus_data
--------------
time                   mean_complaints   mean_passengers
2016-08-28T07:00:00Z   9                 6.5

At 8:00, cq_basic_br executes a query with the time range time >= '7:30' AND time < '8:00'. cq_basic_br writes two points to the bus_data measurement in the downsampled_transportation database:

name: bus_data
--------------
time                   mean_complaints   mean_passengers
2016-08-28T07:30:00Z   9                 7.5

[…]

At 9:00, cq_basic_br executes a query with the time range time >= '8:30' AND time < '9:00'. cq_basic_br writes two points to the bus_data measurement in the downsampled_transportation database:

name: bus_data
--------------
time                   mean_complaints   mean_passengers
2016-08-28T08:30:00Z   7                 16

Results:

> SELECT * FROM "downsampled_transportation."autogen"."bus_data"
name: bus_data
--------------
time                   mean_complaints   mean_passengers
2016-08-28T07:00:00Z   9                 6.5
2016-08-28T07:30:00Z   9                 7.5
2016-08-28T08:00:00Z   8                 11.5
2016-08-28T08:30:00Z   7                 16
Example 4: Automatically downsample data and configure the CQ time boundaries


Use an offset interval in the GROUP BY time() clause to alter both the CQ’s default execution time and preset time boundaries.

CREATE CONTINUOUS QUERY "cq_basic_offset" ON "transportation"
BEGIN
  SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h,15m)
END

cq_basic_offsetcalculates the average hourly number of passengers from the bus_data measurement and stores the results in the average_passengers measurement.

cq_basic_offset executes at one-hour intervals, the same interval as the GROUP BY time() interval. The 15 minute offset interval forces the CQ to execute 15 minutes after the default execution time; cq_basic_offset executes at 8:15 instead of 8:00.

Every hour, cq_basic_offset runs a single query that covers the time range between now() and now() minus the GROUP BY time() interval, that is, the time range between now() and one hour prior to now(). The 15 minute offset interval shifts forward the generated preset time boundaries in the CQ’s WHERE clause; cq_basic_offset queries between 7:15 and 8:14 instead of 7:00 and 7:59 .

Annotated log output on the morning of August 28, 2016:

At 8:15 cq_basic_offset executes a query with the time range time >= '7:15' AND time < '8:15'.
cq_basic_offset writes one point to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T07:15:00Z   7.75

At 9:15 cq_basic_offset executes a query with the time range time >= '8:15' AND time < '9:15'.
cq_basic_offset writes one point to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T08:15:00Z   16.75

Results:

> SELECT * FROM "average_passengers"
name: average_passengers
------------------------
time                   mean
2016-08-28T07:15:00Z   7.75
2016-08-28T08:15:00Z   16.75

Notice that the timestamps are for 7:15 and 8:15 instead of 7:00 and 8:00.

Common Issues with Basic Syntax

Issue 1: Handling time intervals with no data


CQs do not write any results for a time interval if no data fall within that time range.

Note that the basic syntax does not support using fill() to change the value reported for intervals with no data. Basic syntax CQs ignore fill() if it’s included in the CQ query. A possible workaround is to use the advanced CQ syntax.

Issue 2: Resampling previous time intervals


The basic CQ runs a single query that covers the time range between now() and now() minus the GROUP BY time() interval. See the advanced syntax for how to configure the query’s time range.

Issue 3: Backfilling results for older data


CQs operate on realtime data, that is, data with timestamps that occur relative to now(). Use a basic INTO query to backfill results for data with older timestamps.

Issue 4: Missing tags in the CQ results


By default, all INTO queries convert any tags in the source measurement to fields in the destination measurement.

Include GROUP BY * in the CQ to preserve tags in the destination measurement.

Advanced Syntax

CREATE CONTINUOUS QUERY <cq_name> ON <database_name>
RESAMPLE EVERY <interval> FOR <interval>
BEGIN
  <cq_query>
END

Description of Advanced Syntax

The cq_query


See Description of Basic Syntax.

Schedule and Coverage


CQs operate on realtime data. With the advanced syntax, CQs use the local server’s timestamp, the information in the RESAMPLE clause, and InfluxDB’s preset time boundaries to determine when to execute and what time range to cover in the query.

CQs execute at the same interval as the EVERY interval in the RESAMPLE clause, and they run at the start of InfluxDB’s preset time boundaries. If the EVERY interval is two hours, InfluxDB executes the CQ at the top of every other hour.

When the CQ executes, it runs a single query for the time range between now() and now() minus the FOR interval in the RESAMPLE clause. If the FOR interval is two hours and the current time is 17:00, the query’s time range is between 15:00 and 16:59.

Both the EVERY interval and the FOR interval accept duration literals. The RESAMPLE clause works with either or both of the EVERY and FOR intervals configured. CQs default to the relevant basic syntax behavior if the EVERY interval or FOR interval is not provided (see the first issue in Common Issues with Advanced Syntax for an anomalistic case).

Examples of Advanced Syntax

The examples below use the following sample data in the transportation database. The measurement bus_data stores 15-minute resolution data on the number of bus passengers:

name: bus_data
--------------
time                   passengers
2016-08-28T06:30:00Z   2
2016-08-28T06:45:00Z   4
2016-08-28T07:00:00Z   5
2016-08-28T07:15:00Z   8
2016-08-28T07:30:00Z   8
2016-08-28T07:45:00Z   7
2016-08-28T08:00:00Z   8
2016-08-28T08:15:00Z   15
2016-08-28T08:30:00Z   15
2016-08-28T08:45:00Z   17
2016-08-28T09:00:00Z   20
Example 1: Configure the execution interval


Use an EVERY interval in the RESAMPLE clause to specify the CQ’s execution interval.

CREATE CONTINUOUS QUERY "cq_advanced_every" ON "transportation"
RESAMPLE EVERY 30m
BEGIN
  SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h)
END

cq_advanced_every calculates the one-hour average of passengers from the bus_data measurement and stores the results in the average_passengers measurement in the transportation database.

cq_advanced_every executes at 30-minute intervals, the same interval as the EVERY interval. Every 30 minutes, cq_advanced_every runs a single query that covers the time range for the current time bucket, that is, the one-hour time bucket that intersects with now().

Annotated log output on the morning of August 28, 2016:

At 8:00, cq_advanced_every executes a query with the time range WHERE time >= '7:00' AND time < '8:00'.
cq_advanced_every writes one point to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   7

At 8:30, cq_advanced_every executes a query with the time range WHERE time >= '8:00' AND time < '9:00'.
cq_advanced_every writes one point to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T08:00:00Z   12.6667

At 9:00, cq_advanced_every executes a query with the time range WHERE time >= '8:00' AND time < '9:00'.
cq_advanced_every writes one point to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T08:00:00Z   13.75

Results:

> SELECT * FROM "average_passengers"
name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   7
2016-08-28T08:00:00Z   13.75

Notice that cq_advanced_every calculates the result for the 8:00 time interval twice. First, it runs at 8:30 and calculates the average for every available data point between 8:00 and 9:00 (8,15, and 15). Second, it runs at 9:00 and calculates the average for every available data point between 8:00 and 9:00 (8, 15, 15, and 17). Because of the way InfluxDB handles duplicate points , the second result simply overwrites the first result.

Example 2: Configure the CQ’s time range for resampling


Use a FOR interval in the RESAMPLE clause to specify the length of the CQ’s time range.

CREATE CONTINUOUS QUERY "cq_advanced_for" ON "transportation"
RESAMPLE FOR 1h
BEGIN
  SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(30m)
END

cq_advanced_for calculates the 30-minute average of passengers from the bus_data measurement and stores the results in the average_passengers measurement in the transportation database.

cq_advanced_for executes at 30-minute intervals, the same interval as the GROUP BY time() interval. Every 30 minutes, cq_advanced_for runs a single query that covers the time range between now() and now() minus the FOR interval, that is, the time range between now() and one hour prior to now().

Annotated log output on the morning of August 28, 2016:

At 8:00 cq_advanced_for executes a query with the time range WHERE time >= '7:00' AND time < '8:00'.
cq_advanced_for writes two points to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   6.5
2016-08-28T07:30:00Z   7.5

At 8:30 cq_advanced_for executes a query with the time range WHERE time >= '7:30' AND time < '8:30'.
cq_advanced_for writes two points to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T07:30:00Z   7.5
2016-08-28T08:00:00Z   11.5

At 9:00 cq_advanced_for executes a query with the time range WHERE time >= '8:00' AND time < '9:00'.
cq_advanced_for writes two points to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T08:00:00Z   11.5
2016-08-28T08:30:00Z   16

Notice that cq_advanced_for will calculate the result for every time interval twice. The CQ calculates the average for the 7:30 time interval at 8:00 and at 8:30, and it calculates the average for the 8:00 time interval at 8:30 and 9:00.

Results:

> SELECT * FROM "average_passengers"
name: average_passengers
------------------------
time                   mean
2016-08-28T07:00:00Z   6.5
2016-08-28T07:30:00Z   7.5
2016-08-28T08:00:00Z   11.5
2016-08-28T08:30:00Z   16
Example 3: Configure the execution interval and the CQ’s time range


Use an EVERY interval and FOR interval in the RESAMPLE clause to specify the CQ’s execution interval and the length of the CQ’s time range.

CREATE CONTINUOUS QUERY "cq_advanced_every_for" ON "transportation"
RESAMPLE EVERY 1h FOR 90m
BEGIN
  SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(30m)
END

cq_advanced_every_for calculates the 30-minute average of passengers from the bus_data measurement and stores the results in the average_passengers measurement in the transportation database.

cq_advanced_every_for executes at one-hour intervals, the same interval as the EVERY interval. Every hour, cq_advanced_every_for runs a single query that covers the time range between now() and now() minus the FOR interval, that is, the time range between now() and 90 minutes prior to now().

Annotated log output on the morning of August 28, 2016:

At 8:00 cq_advanced_every_for executes a query with the time range WHERE time >= '6:30' AND time < '8:00'.
cq_advanced_every_for writes three points to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T06:30:00Z   3
2016-08-28T07:00:00Z   6.5
2016-08-28T07:30:00Z   7.5

At 9:00 cq_advanced_every_for executes a query with the time range WHERE time >= '7:30' AND time < '9:00'.
cq_advanced_every_for writes three points to the average_passengers measurement:

name: average_passengers
------------------------
time                   mean
2016-08-28T07:30:00Z   7.5
2016-08-28T08:00:00Z   11.5
2016-08-28T08:30:00Z   16

Notice that cq_advanced_every_for will calculate the result for every time interval twice. The CQ calculates the average for the 7:30 interval at 8:00 and 9:00.

Results:

> SELECT * FROM "average_passengers"
name: average_passengers
------------------------
time                   mean
2016-08-28T06:30:00Z   3
2016-08-28T07:00:00Z   6.5
2016-08-28T07:30:00Z   7.5
2016-08-28T08:00:00Z   11.5
2016-08-28T08:30:00Z   16
Example 4: Configure the CQ’s time range and fill empty results


Use a FOR interval and fill() to change the value reported for time intervals with no data. Note that at least one data point must fall within the FOR interval for fill() to operate. If no data fall within the FOR interval the CQ writes no points to the destination measurement.

CREATE CONTINUOUS QUERY "cq_advanced_for_fill" ON "transportation"
RESAMPLE FOR 2h
BEGIN
  SELECT mean("passengers") INTO "average_passengers" FROM "bus_data" GROUP BY time(1h) fill(1000)
END

cq_advanced_for_fill calculates the one-hour average of passengers from the bus_data measurement and stores the results in the average_passengers measurement in the transportation database. Where possible, it writes the value 1000 for time intervals with no results.

cq_advanced_for_fill executes at one-hour intervals, the same interval as the GROUP BY time() interval. Every hour, cq_advanced_for_fill runs a single query that covers the time range between now() and now() minus the FOR interval, that is, the time range between now() and two hours prior to now().

Annotated log output on the morning of August 28, 2016:

At 6:00, cq_advanced_for_fill executes a query with the time range WHERE time >= '4:00' AND time < '6:00'.
cq_advanced_for_fill writes nothing to average_passengers; bus_data has no data that fall within that time range.

At 7:00, cq_advanced_for_fill executes a query with the time range WHERE time >= '5:00' AND time < '7:00'.
cq_advanced_for_fill writes two points to average_passengers:

name: average_passengers
------------------------
time                   mean
2016-08-28T05:00:00Z   1000          <------ fill(1000)
2016-08-28T06:00:00Z   3             <------ average of 2 and 4

[…]

At 11:00, cq_advanced_for_fill executes a query with the time range WHERE time >= '9:00' AND time < '11:00'.
cq_advanced_for_fill writes two points to average_passengers:

name: average_passengers
------------------------
2016-08-28T09:00:00Z   20            <------ average of 20
2016-08-28T10:00:00Z   1000          <------ fill(1000)     

At 12:00, cq_advanced_for_fill executes a query with the time range WHERE time >= '10:00' AND time < '12:00'.
cq_advanced_for_fill writes nothing to average_passengers; bus_data has no data that fall within that time range.

Results:

> SELECT * FROM "average_passengers"
name: average_passengers
------------------------
time                   mean
2016-08-28T05:00:00Z   1000
2016-08-28T06:00:00Z   3
2016-08-28T07:00:00Z   7
2016-08-28T08:00:00Z   13.75
2016-08-28T09:00:00Z   20
2016-08-28T10:00:00Z   1000

Note: fill(previous) doesn’t fill the result for a time interval if the previous value is outside the query’s time range. See Frequently Asked Questions for more information.

Common Issues with Advanced Syntax

Issue 1: If the EVERY interval is greater than the GROUP BY time() interval


If the EVERY interval is greater than the GROUP BY time() interval, the CQ executes at the same interval as the EVERY interval and runs a single query that covers the time range between now() and now() minus the EVERY interval (not between now() and now() minus the GROUP BY time() interval).

For example, if the GROUP BY time() interval is 5m and the EVERY interval is 10m, the CQ executes every ten minutes. Every ten minutes, the CQ runs a single query that covers the time range between now() and now() minus the EVERY interval, that is, the time range between now() and ten minutes prior to now().

This behavior is intentional and prevents the CQ from missing data between execution times.

Issue 2: If the FOR interval is less than the execution interval


If the FOR interval is less than the GROUP BY time() interval or, if specified, the EVERY interval, InfluxDB returns the following error:

error parsing query: FOR duration must be >= GROUP BY time duration: must be a minimum of <minimum-allowable-interval> got <user-specified-interval>

To avoid missing data between execution times, the FOR interval must be equal to or greater than the GROUP BY time() interval or, if specified, the EVERY interval.

Currently, this is the intended behavior. GitHub Issue #6963 outlines a feature request for CQs to support gaps in data coverage.

Continuous Query Management

Only admin users are allowed to work with CQs. For more on user privileges, see Authentication and Authorization.

List CQs

List every CQ on an InfluxDB instance with:

SHOW CONTINUOUS QUERIES

SHOW CONTINUOUS QUERIES groups results by database.

Example


The output shows that the telegraf and mydb databases have CQs:

> SHOW CONTINUOUS QUERIES
name: _internal
---------------
name   query


name: telegraf
--------------
name           query
idle_hands     CREATE CONTINUOUS QUERY idle_hands ON telegraf BEGIN SELECT min(usage_idle) INTO telegraf.autogen.min_hourly_cpu FROM telegraf.autogen.cpu GROUP BY time(1h) END
feeling_used   CREATE CONTINUOUS QUERY feeling_used ON telegraf BEGIN SELECT mean(used) INTO downsampled_telegraf.autogen.:MEASUREMENT FROM telegraf.autogen./.*/ GROUP BY time(1h) END


name: downsampled_telegraf
--------------------------
name   query


name: mydb
----------
name      query
vampire   CREATE CONTINUOUS QUERY vampire ON mydb BEGIN SELECT count(dracula) INTO mydb.autogen.all_of_them FROM mydb.autogen.one GROUP BY time(5m) END

Delete CQs

Delete a CQ from a specific database with:

DROP CONTINUOUS QUERY <cq_name> ON <database_name>

DROP CONTINUOUS QUERY returns an empty result.

Example


Drop the idle_hands CQ from the telegraf database:

> DROP CONTINUOUS QUERY "idle_hands" ON "telegraf"`
>

Alter CQs

CQs cannot be altered once they’re created. To change a CQ, you must DROP and reCREATE it with the updated settings.

Continuous Query Use Cases

Downsampling and Data Retention

Use CQs with InfluxDB’s retention policies (RPs) to mitigate storage concerns. Combine CQs and RPs to automatically downsample high precision data to a lower precision and remove the dispensable, high precision data from the database.

See the Downsampling and Data Retention guide for a detailed walkthrough of this common use case.

Pre-calculating Expensive Queries

Shorten query runtimes by pre-calculating expensive queries with CQs. Use a CQ to automatically downsample commonly-queried, high precision data to a lower precision. Queries on lower precision data require fewer resources and return faster.

Tip: Pre-calculate queries for your preferred graphing tool to accelerate the population of graphs and dashboards.

Substituting for a HAVING Clause

InfluxQL does not support [HAVING clauses](https://en.wikipedia.org/wiki/Having_(SQL)). Get the same functionality by creating a CQ to aggregate the data and querying the CQ results to apply the HAVING clause.

Example


InfluxDB does not accept the following query with a HAVING clause. The query calculates the average number of bees at 30 minute intervals and requests averages that are greater than 20.

SELECT mean("bees") FROM "farm" GROUP BY time(30m) HAVING mean("bees") > 20

To get the same results:

1. Create a CQ

This step performs the mean("bees") part of the query above. Because this step creates CQ you only need to execute it once.

The following CQ automatically calculates the average number of bees at 30 minutes intervals and writes those averages to the mean_bees field in the aggregate_bees measurement.

CREATE CONTINUOUS QUERY "bee_cq" ON "mydb" BEGIN SELECT mean("bees") AS "mean_bees" INTO "aggregate_bees" FROM "farm" GROUP BY time(30m) END

2. Query the CQ results

This step performs the HAVING mean("bees") > 20 part of the query above.

Query the data in the measurement aggregate_bees and request values of the mean_bees field that are greater than 20 in the WHERE clause:

SELECT "mean_bees" FROM "aggregate_bees" WHERE "mean_bees" > 20

Substituting for Nested Functions

Some InfluxQL functions support nesting of other functions. Most do not. If your function does not support nesting, you can get the same functionality using a CQ to calculate the inner-most function. Then simply query the CQ results to calculate the outer-most function.

Example


InfluxDB does not accept the following query with a nested function. The query calculates the number of non-null values of bees at 30 minute intervals and the average of those counts:

SELECT mean(count("bees")) FROM "farm" GROUP BY time(30m)

To get the same results:

1. Create a CQ

This step performs the count("bees") part of the nested function above. Because this step creates a CQ you only need to execute it once.

The following CQ automatically calculates the number of non-null values of bees at 30 minute intervals and writes those counts to the count_bees field in the aggregate_bees measurement.

CREATE CONTINUOUS QUERY "bee_cq" ON "mydb" BEGIN SELECT count("bees") AS "count_bees" INTO "aggregate_bees" FROM "farm" GROUP BY time(30m) END

2. Query the CQ results

This step performs the mean([...]) part of the nested function above.

Query the data in the measurement aggregate_bees to calculate the average of the count_bees field:

SELECT mean("count_bees") FROM "aggregate_bees" WHERE time >= <start_time> AND time <= <end_time>

Further Reading

We recommend visiting the Downsampling and Data Retention guide to see how to combine two InfluxDB features, CQs and retention policies, to periodically downsample data and automatically expire the dispensable high precision data.

Kapacitor, InfluxData’s data processing engine, can do the same work as InfluxDB’s CQs. Check out the Kapacitor documentation for when to use Kapacitor instead of InfluxDB and how to perform the same CQ functionality with a TICKscript.