Statements
This page lists each statement family with its exact grammar, behaviour, and caveats. For expression details (operators, CASE, IN, subqueries) see Expressions & operators.
SELECT
Section titled “SELECT”SELECT [DISTINCT] column [AS alias], ...FROM table [[AS] alias] [JOIN ...]WHERE conditionGROUP BY expr, ...HAVING conditionORDER BY expr [ASC|DESC], ...LIMIT n [OFFSET m];SELECTwithoutFROMevaluates an expression (SELECT 1 + 2,SELECT upper('hi')).DISTINCTde-duplicates the result row set.ORDER BYaccepts expressions, column aliases, and 1-based ordinal positions (ORDER BY 2).LIMIT/OFFSETaccept numeric expressions.- Set operations:
UNION,UNION ALL,INTERSECT, andEXCEPTare supported with standard precedence (INTERSECTbinds tighter thanUNION/EXCEPT). A compound query’sORDER BY/LIMIT/OFFSETapply to the combined result. - Subqueries are supported in
FROM(derived tables require an alias), as scalar expressions, inIN (SELECT ...), and inEXISTS (SELECT ...), including correlated subqueries.
FROM a JOIN b ON a.id = b.a_idFROM a INNER JOIN b ON ...FROM a LEFT [OUTER] JOIN b ON ...FROM a CROSS JOIN bFROM a, b -- implicit cross join, filtered by WHEREINNER,LEFT, andCROSSjoins are fully executed.LEFT JOINproduces a NULL-padded row for unmatched left rows.- Equality joins (
ON a.x = b.y) use a hash join; non-equalityONconditions fall back to a nested loop. RIGHT [OUTER] JOINandFULL [OUTER] JOINparse but are not executed — they return an empty result. Rewrite withLEFT JOIN.NATURAL JOINandUSING (cols)parse but their join condition is ignored, effectively becoming a cross join. Always use an explicitON.
INSERT
Section titled “INSERT”INSERT INTO table [(col, ...)] VALUES (expr, ...), (expr, ...);INSERT INTO table [(col, ...)] SELECT ...;INSERT OR REPLACE INTO table ...;INSERT OR IGNORE INTO table ...;INSERT OR FAIL INTO table ...;INSERT OR ABORT INTO table ...;INSERT INTO table ... ON CONFLICT [(pk)] DO NOTHING;INSERT INTO table ... ON CONFLICT [(pk)] DO UPDATE SET col = expr, ...;- Omitting the column list targets all columns in declaration order.
INSERT ... SELECTbulk-inserts the materialized result.- Conflict handling is driven by the primary key only:
INSERT OR IGNOREsilently skips duplicate-PK rows.INSERT OR REPLACEdeletes the conflicting row and inserts the new one.INSERT OR FAIL/OR ABORTabort on the first duplicate.ON CONFLICT (target) DO NOTHING/DO UPDATE SET ...work only when the conflict is on the primary key; the(target)list must name the PK column (or be omitted).
- Auto-generated integer primary keys (and the implicit rowid) are assigned when no PK value is supplied. There is no
RETURNING, butSELECT last_insert_rowid()returns the rowid of the most recent successfulINSERTon this connection (see Functions).
UPDATE and DELETE
Section titled “UPDATE and DELETE”UPDATE table SET col = expr, ... WHERE condition;DELETE FROM table WHERE condition;- Both evaluate the
WHEREcondition per row.UPDATEevaluatesSETexpressions against the row’s current values, soSET balance = balance + 100works. - Omitting
WHEREaffects every row. - No
RETURNING, noORDER BY/LIMITonUPDATE/DELETE.
CREATE TABLE
Section titled “CREATE TABLE”CREATE TABLE [IF NOT EXISTS] table ( column TYPE [PRIMARY KEY] [NOT NULL] [DEFAULT expr] [AUTOINCREMENT], ..., [PRIMARY KEY (col, ...)], [UNIQUE (col, ...)], [CHECK (expr)], [FOREIGN KEY (col) REFERENCES other (col)]);IF NOT EXISTSsilently succeeds if the table already exists.PRIMARY KEY,NOT NULL, andDEFAULThave an effect;AUTOINCREMENTis accepted but adds no behavior. Inline and table-levelUNIQUEconstraints are materialized into unique indexes and enforced on the core write paths — see Constraints.CHECKandFOREIGN KEYare still parsed and discarded.- A table-level
PRIMARY KEY (a, b)uses the first named column as the primary key; composite keys are not truly supported. DEFAULT expris evaluated when the table is created, so it must be a constant expression. Signed numeric literals (DEFAULT -1,DEFAULT +5,DEFAULT (-7)) are accepted.- A bare
NULLcolumn specifier is accepted as a no-op (columns are nullable by default);NOT NULLstill applies whenever it appears. AUTOINCREMENTis accepted but has no extra behaviour over a plainINTEGER PRIMARY KEY.
ALTER TABLE
Section titled “ALTER TABLE”ALTER TABLE table ADD COLUMN column TYPE [constraints];ALTER TABLE table DROP COLUMN column;ALTER TABLE table RENAME TO new_name;ALTER TABLE table RENAME COLUMN old TO new;ADD COLUMNappends a nullable column;ADD COLUMN IF NOT EXISTS column ...is also accepted.- You cannot drop the primary-key column.
- Renaming is schema-only; index definitions referencing renamed columns are not updated automatically.
CREATE / DROP INDEX and VIEW
Section titled “CREATE / DROP INDEX and VIEW”CREATE [UNIQUE] INDEX [IF NOT EXISTS] name ON table (col [ASC|DESC], ...);DROP INDEX [IF EXISTS] name;
CREATE VIEW [IF NOT EXISTS] view AS SELECT ...;DROP VIEW [IF EXISTS] view;- Index definitions persist, but index entries are rebuilt in memory and only used for single-column equality lookups — see Indexes.
UNIQUEindexes are recorded as unique in the catalog and enforced on the core write paths via validating scans;CREATE UNIQUE INDEXrejects a table that already contains duplicate non-NULLvalues.- Views are connection-local and in-memory: they exist only within the connection that created them and are not persisted or shared. See Catalog & schema.
Transactions
Section titled “Transactions”BEGIN [TRANSACTION];COMMIT;ROLLBACK;SAVEPOINT name;RELEASE name;ROLLBACK TO name;- Transactions stage DML and use optimistic compare-and-batch validation at commit. They are not PostgreSQL MVCC, and DDL is not transactional. See Transactions.
SAVEPOINToutside a transaction implicitly starts one.- On the managed HTTP endpoint, transaction statements are rejected with
501. Over the PostgreSQL wire proxy, transactions are forwarded and work normally.
PRAGMA and EXPLAIN
Section titled “PRAGMA and EXPLAIN”PRAGMA table_info(t); -- column list for table tPRAGMA table_xinfo(t); -- table_info columns plus a trailing hidden flagPRAGMA index_list(t); -- indexes on table t (seq, name, unique, origin, partial)PRAGMA index_info(idx); -- columns of index idx (seqno, cid, name)PRAGMA table_list; -- all tablesPRAGMA database_list; -- attached databasesPRAGMA version; -- engine version
EXPLAIN stmt; -- simplified opcode listingEXPLAIN QUERY PLAN stmt; -- SCAN/FILTER/SORT/LIMIT descriptiontable_xinfo,index_list, andindex_infoexist to satisfy SQLite migrators (GORM/XORM); they are answered from the durable schema, not a real SQLite file.- Only the
PRAGMAforms above are implemented; any other pragma name errors. EXPLAINoutput is illustrative only — it does not reflect the real execution engine (there is no cost-based planner; see Query lifecycle).
SQLite catalog tables
Section titled “SQLite catalog tables”sqlite_master and sqlite_schema are emulated as read-only virtual tables whose rows are synthesized from the durable schema (type, name, tbl_name, rootpage, sql). Single-table SELECT queries against them work for migrator introspection; they are not real writable SQLite catalog tables and are not persisted. See PostgreSQL protocol.
ATTACH / DETACH DATABASE
Section titled “ATTACH / DETACH DATABASE”ATTACH DATABASE 'name' AS alias;DETACH DATABASE alias;ATTACHregisters another database namespace (each database is a key prefix in PizzaKV) under an alias. Aliasesmain,temp, andtemporaryare reserved.DETACHcannot detachmain. Detaching does not drop the underlying database data.
Not supported
Section titled “Not supported”These are rejected at parse time: RETURNING, WITHOUT ROWID, TRUNCATE, UPSERT (beyond the OR/ON CONFLICT forms), triggers, and CREATE SCHEMA/roles. Window functions other than ROW_NUMBER() OVER (PARTITION BY ... ORDER BY ...) are also rejected.