Binding inputs
Features defined with INPUT() are placeholders — they declare what a feature needs, not what value it has. Binding is how you provide those concrete values so the query can actually execute.
FeatureQL offers several binding operators depending on where your data comes from:
| Operator | What it does | Typical use case |
|---|---|---|
BIND_VALUE() | Binds a single value | Testing, simple parameterization |
BIND_VALUES() | Binds an array of values | Prototyping, small batch processing |
BIND_COLUMNS() | Binds columns from a table or query | Production batch processing |
@BIND_KEYSET() | Binds entity keys from a predefined set | Offline analytics at scale |
How binding affects result cardinality
The number of rows you get back depends on how many values you bind and whether you bind features together or separately:
- Single feature, n values → n rows.
- Multiple features, single binding (using
ROW()): n value pairs → n rows. The values are paired positionally. - Multiple features, separate bindings (requires
FOR CROSS): n values × m values → n × m rows. FeatureQL produces the Cartesian product of all combinations.
Bind a single value
The simplest case: one value per input. Derived features are computed automatically from the bound values.
WITH
NAME := INPUT(VARCHAR), -- Declare an input of type VARCHAR
HELLO := 'Hello, ' || NAME || '!',
NUMBER := INPUT(BIGINT), -- Declare an input of type BIGINT
OTHER_NUMBER := NUMBER * 2,
SELECT
NAME,
HELLO,
NUMBER,
OTHER_NUMBER
FOR CROSS
NAME := BIND_VALUE('FeatureQL'),
NUMBER := BIND_VALUE(5),
;| NAME VARCHAR | HELLO VARCHAR | NUMBER BIGINT | OTHER_NUMBER BIGINT |
|---|---|---|---|
| FeatureQL | Hello, FeatureQL! | 5 | 10 |
Bind multiple values
For batch workloads, bind an array of values to evaluate a feature across many inputs at once.
One feature
Pass an array to BIND_VALUES(). Each element produces one result row.
WITH
INPUT1 := INPUT(BIGINT),
CALCULATED := INPUT1 + 1
SELECT
INPUT1,
CALCULATED,
FOR
INPUT1 := BIND_VALUES(ARRAY[1, 3, 5]),
;| INPUT1 BIGINT | CALCULATED VARCHAR |
|---|---|
| 1 | 2 |
| 3 | 4 |
| 5 | 6 |
Multiple features, paired
To bind several features together, wrap each set of values in a ROW(). The first row goes with the first row, second with second, and so on — no cross-product.
WITH
INPUT1 := INPUT(BIGINT),
INPUT2 := INPUT(BIGINT),
CALCULATED := INPUT1 + INPUT2
SELECT
INPUT1,
INPUT2,
CALCULATED
FOR
(INPUT1, INPUT2) := BIND_VALUES(ARRAY[ROW(1, 2), ROW(3, 4), ROW(5, 6)]),
;| INPUT1 BIGINT | INPUT2 BIGINT | CALCULATED VARCHAR |
|---|---|---|
| 1 | 2 | 3 |
| 3 | 4 | 7 |
| 5 | 6 | 11 |
Multiple features, separate (Cartesian product)
When you bind features with separate BIND_VALUES() calls, FeatureQL evaluates every combination. Three values for each of two features produces 3 × 3 = 9 rows.
Because cross products can produce unexpectedly large result sets, FeatureQL requires the explicit FOR CROSS keyword instead of plain FOR. This makes the intent clear and prevents accidental Cartesian products when you meant to pair values. If you want pairing instead, use ROW() tuples in a single BIND_VALUES() as shown above.
WITH
FEATUREF1 := INPUT(BIGINT),
FEATUREF2 := INPUT(BIGINT),
FEATUREFF := FEATUREF1 + FEATUREF2,
SELECT
FEATUREF1,
FEATUREF2,
FEATUREFF,
FOR CROSS
FEATUREF1 := BIND_VALUES(ARRAY[1, 3, 5]),
FEATUREF2 := BIND_VALUES(ARRAY[2, 4, 6]),
;| FEATUREF1 BIGINT | FEATUREF2 BIGINT | FEATUREFF VARCHAR |
|---|---|---|
| 1 | 2 | 3 |
| 1 | 4 | 5 |
| 1 | 6 | 7 |
| 3 | 2 | 5 |
| 3 | 4 | 7 |
| 3 | 6 | 9 |
| 5 | 2 | 7 |
| 5 | 4 | 9 |
| 5 | 6 | 11 |
Bind to external data
When your input values live in a database table, use BIND_COLUMNS() to pull them in directly. First, let's create a sample table:
/* SQL */
CREATE SCHEMA IF NOT exists bnd;
--
CREATE OR REPLACE TABLE bnd.table_example AS
SELECT unnest as col_key, unnest+1 as val1, unnest*2 as val2 FROM unnest(ARRAY[1,2,3]);| Count BIGINT |
|---|
| 3 |
Then bind columns from that table to features. The query evaluates once per row in the source table.
WITH
INPUT1 := INPUT(BIGINT),
INPUT2 := INPUT(BIGINT),
ADD_INPUTS := INPUT1 + INPUT2,
SELECT
INPUT1,
INPUT2,
ADD_INPUTS,
FOR
(INPUT1, INPUT2) := BIND_COLUMNS(val1, val2 FROM TABLE(bnd.table_example)),| INPUT1 BIGINT | INPUT2 BIGINT | ADD_INPUTS BIGINT |
|---|---|---|
| 2 | 2 | 4 |
| 3 | 4 | 7 |
| 4 | 6 | 10 |
Using sets of keys
For analytics at scale, you can use predefined sets of entity keys with the metaprogramming function @BIND_KEYSET(). This is especially useful for offline batch analytics where you want to evaluate features for all entities matching certain business criteria.
More details in the bind keyset section.