Skip to Content

The binder currently supports one relation, derived table, table function, or supported left-deep join chain in FROM; it also supports no FROM for constant expressions.

SELECT a, b + 1 AS b1 FROM events WHERE a > 10 ORDER BY b1 LIMIT 50;

FROM-first query syntax is also accepted:

FROM events SELECT a, b + 1 AS b1 WHERE a > 10 LIMIT 50;

Use standard SELECT ... FROM ... syntax unless you are intentionally matching DuckDB-style examples.

FROM

Supported FROM items:

  • a registered table
  • a non-lateral derived table
  • a table function call
  • one table alias; column alias lists are supported for derived tables and CTEs

Examples:

SELECT * FROM events AS e LIMIT 10;
SELECT function_set, summary FROM spql.meta.table_functions() WHERE visibility = 'public';
SELECT recent.id, recent.score FROM ( SELECT id, score FROM events WHERE score > 0 ) AS recent;

Not yet supported:

  • join shapes outside left-deep INNER JOIN ... ON field-reference equality
  • lateral derived tables
  • lateral table functions
  • nested joins
  • more than one FROM relation

CTEs

Non-recursive CTEs are bound inline and can rename output columns:

WITH totals(category, total_score) AS ( SELECT category, sum(score) FROM events GROUP BY category ) SELECT category, total_score FROM totals WHERE total_score > 100;

Recursive CTEs are not supported.

Projection

Supported:

  • Column references.
  • Expression aliases with AS.
  • Unqualified *.

Projection names are preserved for simple column references and aliases. Generated expression names use column1, column2, and so on.

Not yet supported:

  • Qualified wildcards.
  • Wildcard options such as EXCLUDE, REPLACE, and RENAME.
  • Multi-alias projection items.

Filtering

WHERE accepts supported scalar expressions. See Expressions.

Aggregation

Use GROUP BY with field references or scalar expressions:

SELECT category, count(*) AS rows FROM events GROUP BY category;

Aggregate calls are supported as direct projection items:

SELECT category, sum(score) AS total_score FROM events GROUP BY category;

Expressions in GROUP BY are materialized into generated helper fields before aggregation when needed:

SELECT amount + 1 AS bucket, count(*) AS rows FROM events WHERE amount IS NOT NULL GROUP BY amount + 1 HAVING amount + 1 > 20 ORDER BY bucket;

HAVING is supported for aggregate queries:

SELECT category, count(*) AS rows FROM events GROUP BY category HAVING count(*) > 10;

Current limits:

  • GROUP BY ALL is not supported.
  • Aggregate calls nested inside projection expressions are not supported.

Ordering and limits

ORDER BY supports output field references and scalar expressions. If an ordering expression is not part of the projected output, the binder materializes a generated helper field before sorting or top-k and drops it afterward.

Without LIMIT, only ascending NULLS FIRST ordering is supported. With LIMIT, Spiral uses the Top-K path and can plan descending order and null ordering.

LIMIT and OFFSET must be integer literals.

Examples:

SELECT id, score FROM events ORDER BY score DESC NULLS LAST LIMIT 20;
SELECT id, score FROM events ORDER BY id OFFSET 100 LIMIT 50;
SELECT id FROM events WHERE amount IS NOT NULL ORDER BY amount + 1 LIMIT 20;

Not yet supported

Set operations, DISTINCT, QUALIFY, window functions, recursive CTEs, lateral derived tables, and join shapes outside the supported inner equi-join subset are parsed in some cases but are not yet bound by the current execution path.

Last updated on