diff --git a/documentation/cookbook/sql/time-series/fill-from-one-column.md b/documentation/cookbook/sql/time-series/fill-from-one-column.md index 509248d02..084261995 100644 --- a/documentation/cookbook/sql/time-series/fill-from-one-column.md +++ b/documentation/cookbook/sql/time-series/fill-from-one-column.md @@ -17,18 +17,23 @@ WHERE symbol = 'EURUSD' AND timestamp IN '$today' SAMPLE BY 100T FILL(PREV, PREV); ``` -But when there is an interpolation, instead of getting the PREV value for `bid_price` and previous for `ask_price`, you want both prices to show the PREV known value for the `ask_price`. Imagine this SQL was valid: +But when there is an interpolation, instead of getting the PREV value for `bid_price` and previous for `ask_price`, you want both prices to show the PREV known value for the `ask_price`. -```sql +## Solution + +QuestDB supports referencing another aggregate column by alias inside `PREV()`: + +```questdb-sql demo title="Fill bid_price with previous value of ask_price" SELECT timestamp, symbol, avg(bid_price) as bid_price, avg(ask_price) as ask_price FROM core_price WHERE symbol = 'EURUSD' AND timestamp IN '$today' SAMPLE BY 100T FILL(PREV(ask_price), PREV); ``` -## Solution - -The only way to do this is in multiple steps within a single query: first get the sampled data interpolating with null values, then use a window function to get the last non-null value for the reference column, and finally coalesce the missing columns with this filler value. +The reference must match the target column's type, cannot be broadcast across +aggregates, and is rejected when either side is a `SYMBOL`. For more flexible +cases — for example, marking which rows were filled, or chaining custom +expressions — the equivalent rewrite below uses window functions: ```questdb-sql demo title="Fill bid and ask prices with value from ask price" WITH sampled AS ( diff --git a/documentation/cookbook/sql/time-series/fill-keyed-arbitrary-interval.md b/documentation/cookbook/sql/time-series/fill-keyed-arbitrary-interval.md index ec2604a2b..6efb6070a 100644 --- a/documentation/cookbook/sql/time-series/fill-keyed-arbitrary-interval.md +++ b/documentation/cookbook/sql/time-series/fill-keyed-arbitrary-interval.md @@ -10,10 +10,12 @@ and ending timestamp, not only between the first and last existing row in the fi ## Problem -QuestDB has a built-in [`SAMPLE BY .. FROM/TO`](/docs/query/sql/sample-by/#from-to) syntax available for non-keyed queries (queries that include only aggregated columns beyond the timestamp), and for the `NULL` FILL strategy. - -If you use `FROM/TO` in a keyed query (for example, an OHLC with timestamp, symbol, and aggregations) you will get the -following error: _FROM-TO intervals are not supported for keyed SAMPLE BY queries_. +QuestDB's [`SAMPLE BY .. FROM/TO`](/docs/query/sql/sample-by/#from-to) supports +keyed queries when `FROM`/`TO` are constants. When the bounds are bind +variables, function calls, or arithmetic expressions (for example, +`dateadd('m', -2, now())`), the query is rejected with: _FROM-TO intervals are +not supported for keyed SAMPLE BY queries_. The recipe below works around this +limitation. ## Solution diff --git a/documentation/query/sql/sample-by.md b/documentation/query/sql/sample-by.md index aba81a330..33ba5a895 100644 --- a/documentation/query/sql/sample-by.md +++ b/documentation/query/sql/sample-by.md @@ -64,20 +64,24 @@ SAMPLE BY 1h; `FILL` specifies how to handle time intervals with no data. By default, missing intervals are skipped. Use `FILL` to interpolate or substitute values. -| fillOption | Description | -| ---------- | ------------------------------------------------------------------------------------------------------------------------- | -| `NONE` | No fill applied. If there is no data, the time sample will be skipped in the results. A table could be missing intervals. | -| `NULL` | Fills with `NULL` values. | -| `PREV` | Fills using the previous value. | -| `LINEAR` | Fills by linear interpolation of the 2 surrounding points. | -| `x` | Fills with a constant value - where `x` is the desired value, for example `FILL(100.05)`. | +| fillOption | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------------------- | +| `NONE` | No fill applied. If there is no data, the time sample will be skipped in the results. A table could be missing intervals. | +| `NULL` | Fills with `NULL` values. | +| `PREV` | Fills using the previous value of the same aggregate column. | +| `PREV(col)` | Fills using the previous value of another aggregate column referenced by alias. | +| `LINEAR` | Fills by linear interpolation of the 2 surrounding points. | +| `x` | Fills with a constant value - where `x` is the desired value, for example `FILL(100.05)`. | The following restrictions apply: -- Keywords denoting fill strategies may not be combined. Only one option from - `NONE`, `NULL`, `PREV`, `LINEAR` and constants may be used. +- `FILL(NONE)` cannot be combined with other fill values; the other strategies + may be mixed in a per-aggregate fill list. - `LINEAR` strategy is not supported for keyed queries, i.e. queries that contain non-aggregated columns other than the timestamp in the SELECT clause. +- `PREV(col)` references another aggregate column by alias and must match its + type. It cannot be broadcast across multiple aggregates and is rejected when + source or target is `SYMBOL`. - The `FILL` keyword must precede alignment described in the [sample calculation section](#sample-calculation), i.e.: @@ -226,7 +230,7 @@ ALIGN TO CALENDAR TIME ZONE 'Europe/Berlin'; Here, `FROM '2026-01-01T00:00:00'` means midnight January 1st in Berlin local time (= `2025-12-31T23:00:00Z` UTC). -`FROM-TO` can only be used on non-keyed SAMPLE BY queries (queries with no grouping columns other than the timestamp). +`FROM-TO` works with both non-keyed and keyed `SAMPLE BY` queries. Keyed queries emit one row per (bucket, key) combination across the full interval. ### `WHERE` clause optimisation @@ -247,10 +251,12 @@ SAMPLE BY 1d FROM '2009-01-01' TO '2009-01-10' FILL(NULL); ### Limitations -- Not compatible with `FILL(PREV)` or `FILL(LINEAR)`. +- Not compatible with `FILL(LINEAR)`. - Only works with `ALIGN TO CALENDAR` (default alignment). -- Does not consider any specified `OFFSET`. -- Only for non-keyed `SAMPLE BY` (designated timestamp and aggregate columns only). See [Fill keyed queries with arbitrary intervals](/docs/cookbook/sql/time-series/fill-keyed-arbitrary-interval/) for a workaround. +- Keyed `FROM-TO` requires `FROM`/`TO` to be constants. Bind variables, + function calls, and arithmetic expressions are rejected for keyed queries. + See [Fill keyed queries with arbitrary intervals](/docs/cookbook/sql/time-series/fill-keyed-arbitrary-interval/) + for a workaround. ## Sample calculation