Use Grafana time range in DECLARE variables

Pass Grafana's dashboard time range into QuestDB DECLARE variables. This is useful when you combine time range filtering with other declared parameters, override parameterized views, or derive additional time boundaries from the dashboard range.

Problem

The QuestDB Grafana plugin provides $__fromTime and $__toTime macros, but they expand to cast(... as timestamp), which DECLARE does not support:

-- What you write
DECLARE @from := $__fromTime, @to := $__toTime
SELECT * FROM trades WHERE timestamp >= @from AND timestamp <= @to;

-- What the plugin sends to QuestDB (fails)
DECLARE @from := cast(1654380000000000 as timestamp), ...
-- Error: table and column names that are SQL keywords have to be
-- enclosed in double quotes, such as "cast"

Solution

Use $__from and $__to instead. These are Grafana global variables that expand to plain epoch milliseconds, which DECLARE accepts.

Convert milliseconds to the precision your table uses:

  • TIMESTAMP (microseconds): multiply by 1000
  • TIMESTAMP_NS (nanoseconds): multiply by 1000000
TIMESTAMP table (microseconds)
DECLARE
@from := $__from * 1000,
@to := $__to * 1000,
@symbol := 'BTC-USDT'
SELECT timestamp, symbol, avg(price) AS avg_price
FROM trades
WHERE symbol = @symbol
AND timestamp >= @from
AND timestamp <= @to
SAMPLE BY $__interval;
TIMESTAMP_NS table (nanoseconds)
DECLARE
@from := $__from * 1000000,
@to := $__to * 1000000,
@symbol := 'EURUSD'
SELECT timestamp, symbol, avg(price) AS avg_price
FROM fx_trades
WHERE symbol = @symbol
AND timestamp >= @from
AND timestamp <= @to
SAMPLE BY $__interval;

No cast() is needed when the multiplier matches the table's timestamp precision. QuestDB compares the LONG value directly against the timestamp column.

Using cast as a safety net

If you are unsure whether your table uses TIMESTAMP or TIMESTAMP_NS, you can multiply by 1000 (microseconds) and wrap the comparison in cast(... AS timestamp). QuestDB auto-promotes TIMESTAMP to TIMESTAMP_NS when comparing against a nanosecond column, so this works for both types:

Works for both TIMESTAMP and TIMESTAMP_NS tables
DECLARE
@from := $__from * 1000,
@to := $__to * 1000
SELECT timestamp, avg(price) AS avg_price
FROM fx_trades
WHERE timestamp >= cast(@from AS timestamp)
AND timestamp <= cast(@to AS timestamp)
SAMPLE BY $__interval;

When to use this instead of $__timeFilter

$__timeFilter(timestamp) is simpler for straightforward queries:

SELECT timestamp, price FROM trades
WHERE $__timeFilter(timestamp)
SAMPLE BY $__interval;

The DECLARE approach is needed when:

  • You combine the time range with other DECLARE variables in a single block
  • You override a parameterized view whose time range variables must be set
  • You derive additional time boundaries from the dashboard range (for example, a lookback window for a moving average)