SQL & Postgres β€” Reference

Lookup material for the SQL subset. For prose and examples see the Guide; to get started, the Quickstart.

Operator & function quick reference

Everything the subset accepts, at a glance. Anything not listed is rejected loudly (with SQLSTATE 0A000 / 42601), never silently ignored.

CategorySupported
Comparison=, <> / !=, <, <=, >, >=
Set / rangeIN (…), NOT IN (…), BETWEEN a AND b
NullIS NULL, IS NOT NULL (= NULL rejected β€” use IS NULL)
Text matchLIKE 'ap%' (prefix) or exact, NOT LIKE β€” no %ap, %ap%, _, or ILIKE
Full-textcol @@ 'text' or to_tsvector(col) @@ plainto_tsquery('text') β†’ tokenising $match on an analysed column. See Guide
Boolean logicAND, OR, NOT, parentheses
Arithmetic+, -, *, /, parentheses, precedence
String fns|| (concat), concat, upper, lower, length
Scalar fnscoalesce(a, b, …), cast(x AS int|bigint|text|numeric|…)
Aggregatescount(*), count(DISTINCT c), sum, avg, min, max β€” usable inside expressions
Predictionpredict(col) (argmax), predictions(col) ≑ predict(col, probabilities => true) (distribution); PREDICTION/PREDICTIONS aliases β€” inference in SQL; not with GROUP BY. See the Guide
RecommendSELECT * FROM recommend('from','target', goal => '…', given => '…', k => N) β€” set-returning function β†’ (value, p). See the Guide
RelateSELECT * FROM relate('from', fields => '…', to => '…', k => N) β€” set-returning function β†’ (related, lift, info, n). See the Guide
ClausesWHERE, GROUP BY (single col), HAVING, ORDER BY … ASC|DESC (single key), LIMIT, OFFSET
JoinINNER JOIN … ON <base>.<fk> = <joined>.<pk>, along a declared link

Not supported yet (rejected with a clear error, never silently ignored): multiple ORDER BY keys, outer/cross/multi-table JOIN (and joins whose ON is not a declared link), multi-column GROUP BY, per-group min/max, UNION, substring/suffix LIKE and ILIKE, subqueries, and schema-qualified/quoted identifiers. = NULL / <> NULL are rejected with a hint to use IS NULL / IS NOT NULL (matching Postgres's three-valued logic). (INSERT, CREATE TABLE, and CREATE VIEW are supported over the Postgres wire protocol β€” see Writes β€” but not on the read-only /api/v2/_sql endpoint.)

Error codes (SQLSTATE)

Failures are reported with a standard PostgreSQL SQLSTATE, so a Postgres client or connector reacts the way it would to a real Postgres β€” the message is always specific, never a swallowed empty result. Over the wire protocol the code rides in the ErrorResponse; over REST it's in the error JSON.

SQLSTATENameWhen
23505unique_violationINSERT of a duplicate primary key with no (or DO NOTHING-less) ON CONFLICT
42P07duplicate_tableCREATE TABLE / CREATE VIEW of a name that exists (without IF NOT EXISTS / OR REPLACE)
42P01undefined_tableSELECT / INSERT / UPDATE / DELETE / ALTER / DROP on a missing table or view
42701duplicate_columnALTER TABLE ADD COLUMN of a column that exists
42703undefined_columnreference to a column that doesn't exist (ALTER DROP, unknown SET/select column)
0A000feature_not_supporteda valid-Postgres construct Aito doesn't implement yet (outer join, subquery, ILIKE, …)
42601syntax_errora parse error, or an argument the subset rejects (= NULL, '%ap%', a type mismatch)
XX000internal_erroran unexpected server-side failure

IF [NOT] EXISTS turns the otherwise-erroring redundant case (42P07 / 42P01 / 42701 / 42703) into a silent no-op, exactly as in Postgres.

Limitations

  • JOINs follow existing links only: an INNER JOIN along a declared link works (it projects through the link β€” see the Guide), so a tool that sees the foreign key can run the join. Arbitrary joins on non-link columns, and outer/cross/multi-table joins, are still rejected β€” so a postgres_fdw remote join pushdown across two foreign tables isn't supported (join them locally, or disable join pushdown on the foreign server).
  • Writes β€” INSERT (with ON CONFLICT), CREATE TABLE, COPY … FROM STDIN (bulk load), DROP/ALTER TABLE ADD|DROP COLUMN, DELETE, and UPDATE work over the wire protocol (see Writes); the /api/v2/_sql REST endpoint is read-only.
  • Views β€” CREATE [OR REPLACE] VIEW v AS SELECT <cols / renames / *> FROM src [WHERE <equality…>] and DROP VIEW [IF EXISTS] v work over the wire protocol (see Views). A view is a materialised, from-able collection, not stored SELECT text, so SELECT … FROM v β€” including a query-time WHERE/ORDER BY/GROUP BY and even predict/@@ β€” runs on it, and a query WHERE composes on top of the view's baked filter. The view stays current via incremental refresh. v1 limits: a single source (no UNION/JOIN in the definition), and a baked WHERE of equality conditions only (col = v [AND …]); a range/IN/LIKE in a view definition, or an aggregate/GROUP BY, is rejected loud at CREATE VIEW (do it at query time against the view instead).
  • Inference β€” predict/predictions (categorical label columns; not analysed-text/multi-value), full-text @@, recommend(...), and relate(...) are in SQL. Still JSON-only: the raw learned-ranking blends (similarity Γ— contextual $p) β€” those live in the JSON _query API.
  • Metadata depth β€” no composite/unique/check constraints, sequences, indexes, or functions; unrecognised catalog queries return empty rather than erroring, so deep tool features may show nothing.
  • Wire protocol β€” no SCRAM channel binding (-PLUS) or client-certificate auth; TLS is optional, not enforced. Cursors (DECLARE/FETCH) are read-only and materialize the whole result up front (fine for the connectors above, not a streaming cursor over a huge table).