Query structure
A FeatureQL query defines features, selects which ones to return, and binds concrete values to their inputs. You can then filter, sort, and paginate the results — just like SQL.
Anatomy of a query
[WITH
feature_name := expression, -- Feature definition
...
]
SELECT
feature_name, -- Feature to evaluate and return
...
[FROM namespace, ...]
[FOR feature_name := BIND(), ...] -- Bind values to inputs
[WHERE boolean_expression] -- Filter results
[ORDER BY expression [ASC|DESC] [NULLS FIRST|LAST], ...] -- Sort results
[LIMIT count [OFFSET count]] -- Paginate results Each clause has a specific role:
| Clause | Description |
|---|---|
WITH | Defines features locally, on top of what already exists in the registry. |
SELECT | Lists the features to evaluate and return. |
FROM | Defines one or more namespaces to pull features from. |
FOR | Binds concrete values to the query's inputs. Without binding, a query with features depending on INPUT() features won't execute. |
WHERE | Filters the result rows. You can reference any feature at the same granularity as the query. |
ORDER BY | Sorts the results. Supports ASC/DESC and NULLS FIRST/NULLS LAST. |
LIMITOFFSET | Controls pagination. |
Note: GROUP BY and UNNEST are supported for analytics queries. See Grouping and unnesting for details.
Intermediate features with WITH
Complex queries often need intermediate calculations that shouldn't appear in the output. The WITH clause defines features that are available for computation but excluded from the result:
WITH
1 AS NUMBER1, -- Intermediate calculation
2 AS NUMBER2, -- Intermediate calculation
SELECT
NUMBER1, -- Exposed in results
NUMBER1 + NUMBER2 AS NUMBER3 -- Exposed in results
;| NUMBER1 BIGINT | NUMBER3 BIGINT |
|---|---|
| 1 | 3 |
NUMBER2 is used to compute NUMBER3 but doesn't appear in the output. This keeps query results focused on what consumers actually need.
Some functions produce internal values that can't be returned directly:
| Function type | Why it can't be returned | What to return instead |
|---|---|---|
INPUT() | Declares a parameter placeholder | The bound values via BIND_XXX() |
ENTITY() | Declares an entity | The bound values of the INPUT() referencing the entity |
SOURCE_XXX() | Declares a connection | The EXTERNAL_XXX() that uses the source |
UDF()MACRO() | Declares a function | The function applied to concrete parameters |
Example
This example brings it all together: it defines an input with a data source, computes a derived feature, binds values, filters, sorts, and paginates.
WITH
-- Input definitions
CUSTOMER_ID := INPUT(BIGINT),
-- Mapping to data source
DIM_CUSTOMERS := INLINE_COLUMNS(
customer_id BIGINT BIND TO CUSTOMER_ID,
name VARCHAR
FROM CSV(
customer_id,name
101,Alice
102,Bob
103,Charly
104,Daniel
105,Elody
106,Francis
107,George
108,Henry
109,Isaac
110,Jack
)
),
-- Define pure transformations
NAME := DIM_CUSTOMERS[name],
NAME_LENGTH := LENGTH(NAME)
SELECT
-- Features to evaluate and return
CUSTOMER_ID,
NAME,
NAME_LENGTH
FOR
CUSTOMER_ID := BIND_VALUES(SEQUENCE(101, 106)),
WHERE NAME < 'Henry'
ORDER BY NAME DESC
LIMIT 3 OFFSET 1| CUSTOMER_ID BIGINT | NAME VARCHAR | NAME_LENGTH BIGINT |
|---|---|---|
| 105 | Elody | 5 |
| 104 | Daniel | 6 |
| 103 | Charly | 6 |