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:

OperatorWhat it doesTypical use case
BIND_VALUE()Binds a single valueTesting, simple parameterization
BIND_VALUES()Binds an array of valuesPrototyping, small batch processing
BIND_COLUMNS()Binds columns from a table or queryProduction batch processing
@BIND_KEYSET()Binds entity keys from a predefined setOffline 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.

FeatureQL
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),
;
Result
NAME VARCHARHELLO VARCHARNUMBER BIGINTOTHER_NUMBER BIGINT
FeatureQLHello, FeatureQL!510

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.

FeatureQL
WITH
    INPUT1 := INPUT(BIGINT),
    CALCULATED := INPUT1 + 1
SELECT
    INPUT1,
    CALCULATED,
FOR
    INPUT1 := BIND_VALUES(ARRAY[1, 3, 5]),
;
Result
INPUT1 BIGINTCALCULATED VARCHAR
12
34
56

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.

FeatureQL
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)]),
;
Result
INPUT1 BIGINTINPUT2 BIGINTCALCULATED VARCHAR
123
347
5611

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.

FeatureQL
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]),
;
Result
FEATUREF1 BIGINTFEATUREF2 BIGINTFEATUREFF VARCHAR
123
145
167
325
347
369
527
549
5611

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:

FeatureQL
/* 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]);
Result
Count BIGINT
3

Then bind columns from that table to features. The query evaluates once per row in the source table.

FeatureQL
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)),
Result
INPUT1 BIGINTINPUT2 BIGINTADD_INPUTS BIGINT
224
347
4610

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.

Last update at: 2026/03/03 16:47:38
Last updated: 2026-03-03 16:48:19