Skip to content

Expressions ​

Expressions compute values in result columns, WHERE, ORDER BY, SET, CHECK and elsewhere. They follow SQLite's rules for types, NULL and comparisons. For the values themselves, see Data types; for functions, the function reference.

Syntax ​

text
expr:
    literal | column | table.column | schema.table.column | parameter
  | unary-op expr | expr binary-op expr
  | expr [NOT] {LIKE | GLOB} expr [ESCAPE expr]
  | expr [NOT] BETWEEN expr AND expr
  | expr [NOT] IN (expr [, ...]) | expr [NOT] IN (select) | expr [NOT] IN [schema.]table
  | expr IS [NOT] expr | expr IS [NOT] DISTINCT FROM expr
  | expr ISNULL | expr NOTNULL | expr NOT NULL
  | [NOT] EXISTS (select) | (select)
  | CASE [expr] WHEN expr THEN expr [...] [ELSE expr] END
  | CAST (expr AS type-name)
  | expr COLLATE collation
  | function(args) [FILTER (WHERE expr)] [OVER window]
  | (expr)

Operator precedence ​

From tightest to loosest binding. Operators on one line have equal precedence and group left to right.

Operators
unary - + ~, COLLATE
|| -> ->>
* / %
+ -
& | << >>
ESCAPE
< <= > >=
= == != <> IS IS NOT IN LIKE GLOB MATCH REGEXP BETWEEN ISNULL NOTNULL NOT NULL
NOT
AND
OR
sql
SELECT 1 + 2 * 3 AS a, (1 + 2) * 3 AS b, NOT 1 = 2 AS c, 1 = 1 AND 0 OR 1 AS d
abcd
7911

Arithmetic ​

OperatorMeaning
+ - *add, subtract, multiply
/divide; integer division when both operands are integers (truncates toward zero)
%remainder; both operands are converted to integers first, as in SQLite
unary - +negate, no-op
  • Division or remainder by zero gives NULL (no error).
  • Integer arithmetic is exact 64-bit. A result outside the 64-bit range becomes a REAL, as in SQLite.
  • Text and blobs used as numbers take their longest numeric prefix ('3abc' is 3, 'abc' is 0).
  • Any NULL operand gives NULL.
sql
SELECT 7 / 2 AS a, 7.0 / 2 AS b, -7 / 2 AS c, 7 % 3 AS d, 5.5 % 2 AS e, 1 / 0 AS f, '3abc' * 2 AS g, typeof(9223372036854775807 + 1) AS h
abcdefgh
33.5-311NULL6real

Concatenation ​

a || b joins two values as text. Numbers are converted to text the way CAST(… AS TEXT) does (1.0 stays 1.0). NULL on either side gives NULL.

sql
SELECT 'v' || 2 AS a, 'v' || 2.0 AS b, 'v' || NULL AS c
abc
v2v2.0NULL

The JSON operators -> and ->> are parsed but fail with SMALT_UNSUPPORTED.

Bitwise operators ​

& (and), | (or), << and >> (shifts, sign-extending), unary ~ (not), on 64-bit integers.

sql
SELECT 6 & 3 AS a, 6 | 3 AS b, 1 << 4 AS c, -16 >> 2 AS d, ~0 AS e
abcde
2716-4-1

Comparisons ​

= (also ==), != (also <>), <, <=, >, >= return 1, 0, or NULL when either side is NULL.

Values of different types compare in this order: NULL, then INTEGER and REAL (by numeric value), then TEXT (by collation), then BLOB (bytewise). Before comparing, SQLite's affinity rules apply: when one side is a column with INTEGER, REAL or NUMERIC type and the other is text, the text is converted to a number if it looks like one; when one side is a TEXT column and the other a number, the number is converted to text. Two plain literals of different types are not converted.

sql
CREATE TABLE cmp(n INTEGER, t TEXT);
INSERT INTO cmp VALUES (10, '10');
SELECT n = '10' AS num_col, t = 10 AS text_col, 10 = '10' AS literals, 1 = 1.0 AS int_real, 'Z' < 'a' AS binary_text FROM cmp
num_coltext_colliteralsint_realbinary_text
11011

IS, IS NOT, IS DISTINCT FROM ​

a IS b is like = but treats NULLs as equal and never returns NULL. IS NOT is its negation. IS NOT DISTINCT FROM and IS DISTINCT FROM are the standard spellings of IS and IS NOT. x ISNULL, x NOTNULL and x NOT NULL are short for x IS NULL and x IS NOT NULL.

sql
SELECT NULL = NULL AS eq, NULL IS NULL AS is_, 1 IS NOT NULL AS is_not, 1 IS DISTINCT FROM NULL AS distinct_, 5 NOTNULL AS notnull_
eqis_is_notdistinct_notnull_
NULL1111

Logical operators ​

AND, OR and NOT use three-valued logic: NULL means unknown. Any non-zero number is true; text is converted to a number ('abc' is false).

aba AND ba OR b
1NULLNULL1
0NULL0NULL
sql
SELECT 1 AND NULL AS a, 0 AND NULL AS b, 1 OR NULL AS c, NOT NULL AS d
abcd
NULL01NULL

LIKE and GLOB ​

text
expr [NOT] LIKE pattern [ESCAPE char]
expr [NOT] GLOB pattern
LIKEGLOB
any sequence%*
one character_?
character class—[abc], [a-z], [^a-z]
caseASCII letters ignore case ('é' does not match 'É')case-sensitive
escapeESCAPE 'c' makes the next character literaluse a class, e.g. [*]
sql
SELECT 'Hello' LIKE 'h%' AS a, 'Hello' GLOB 'h*' AS b, 'Hello' GLOB 'H?llo' AS c, '50%' LIKE '50\%' ESCAPE '\' AS d, 'Bx' GLOB '[A-C]*' AS e
abcde
10111

MATCH and REGEXP are parsed, but no functions implement them, so they fail with no such function: regexp (SMALT_ERROR), as in SQLite without extensions.

BETWEEN ​

x BETWEEN low AND high is x >= low AND x <= high, with x evaluated once. NOT BETWEEN negates it.

sql
SELECT 5 BETWEEN 1 AND 10 AS a, 'm' BETWEEN 'a' AND 'k' AS b, NULL BETWEEN 1 AND 2 AS c
abc
10NULL

IN ​

text
x [NOT] IN (value, ...)
x [NOT] IN (select)
x [NOT] IN table        -- SQLite shorthand for x IN (SELECT * FROM table)

IN is true when x equals a value in the list or a row of the one-column subquery. When there is no match and the list contains a NULL, the result is NULL (so NOT IN with a NULL in the list is never true). An empty list () is allowed and gives false.

sql
SELECT 2 IN (1, 2) AS a, 3 IN (1, 2) AS b, 3 IN (1, NULL) AS c, 3 NOT IN (1, NULL) AS d, 1 IN () AS e, 2 IN (VALUES (1), (2)) AS f
abcdef
10NULLNULL01

Subqueries ​

A subquery in parentheses is a scalar value: the first column of its first row, or NULL when it returns no rows. It must return one column (sub-select returns 2 columns - expected 1). EXISTS (select) is 1 if the subquery returns any row. Subqueries can refer to columns of the outer query (correlated subqueries).

sql
CREATE TABLE emp(name TEXT, dept TEXT, salary INTEGER);
INSERT INTO emp VALUES ('Ann', 'eng', 100), ('Bob', 'eng', 80), ('Cid', 'ops', 70);
SELECT name,
  salary - (SELECT avg(salary) FROM emp i WHERE i.dept = o.dept) AS vs_dept,
  EXISTS (SELECT 1 FROM emp i WHERE i.dept = o.dept AND i.salary > o.salary) AS has_higher
FROM emp o
ORDER BY name
namevs_depthas_higher
Ann100
Bob-101
Cid00

CASE ​

text
CASE WHEN condition THEN result [WHEN ...] [ELSE result] END
CASE base WHEN value THEN result [WHEN ...] [ELSE result] END

The first WHEN that is true (or equal to base) gives the result; without a match the result is ELSE, or NULL. In the second form, a NULL base matches nothing, not even WHEN NULL.

sql
SELECT name, CASE WHEN salary >= 90 THEN 'high' WHEN salary >= 75 THEN 'mid' ELSE 'low' END AS band,
  CASE dept WHEN 'eng' THEN 'Engineering' ELSE 'Other' END AS dept_name
FROM emp ORDER BY name
namebanddept_name
AnnhighEngineering
BobmidEngineering
CidlowOther

CAST ​

CAST(expr AS type-name) converts a value to the affinity of the type name, using the same rules as column types: a name containing INT is INTEGER, CHAR/CLOB/TEXT is TEXT, BLOB is BLOB, REAL/FLOA/DOUB is REAL, and anything else (including NUMERIC, DECIMAL, BOOLEAN, DATE and ANY) is NUMERIC.

ToFrom textFrom REALFrom BLOB
INTEGERlongest numeric prefix, truncated ('12abc' → 12, 'abc' → 0)truncates toward zero; clamps to the 64-bit rangethe bytes read as text, then converted like text
REALlongest numeric prefixunchangedlike text
TEXTunchangedas SQLite's printf('%!.17g', x): 17 significant digits, fewer when the 17-digit form ends in a run of zeros or nines and the shorter one reads back the same number (0.1, not 0.10000000000000001); always with a decimal point or exponent; the exponent form for exponents below -4 or above 16 (1.0, 1000000000000000.0, 1.0e+17)the bytes as UTF-8
BLOBthe UTF-8 bytesthe text form's bytesunchanged
NUMERICthe numeric prefix, as INTEGER when it is integralunchangedlike text

NULL stays NULL.

sql
SELECT CAST('12abc' AS INTEGER) AS a, CAST(-3.9 AS INTEGER) AS b, CAST(1.0 AS TEXT) AS c, CAST('é' AS BLOB) AS d, CAST(x'414243' AS TEXT) AS e, CAST('12.50' AS DECIMAL) AS f
abcdef
12-31.0x'c3a9'ABC12.5

Unlike storing into a column, CAST never fails.

COLLATE ​

expr COLLATE name sets the collation used when the expression is compared or sorted: BINARY (default; bytewise), NOCASE (ASCII case folded) or RTRIM (trailing spaces ignored). An unknown name fails with no such collation sequence: X. When the two sides of a comparison have different collations, an explicit COLLATE wins, then the left operand's column collation, as in SQLite. See collations.

sql
SELECT 'abc' = 'ABC' AS plain, 'abc' = 'ABC' COLLATE NOCASE AS nocase, 'x  ' = 'x' COLLATE RTRIM AS rtrim
plainnocasertrim
011

Parameters and special values ​

Parameters (?, ?NNN, :name, @name, $name) are described in the lexical structure. CURRENT_DATE, CURRENT_TIME and CURRENT_TIMESTAMP give the current UTC date (YYYY-MM-DD), time (HH:MM:SS) and both (YYYY-MM-DD HH:MM:SS); the current time is read once per statement, so every row sees the same value.

Not supported ​

ExpressionResult
row values: (a, b) = (1, 2), (a, b) IN (…)syntax error: row values are not supported
->, ->>SMALT_UNSUPPORTED
MATCH, REGEXPno such function
RAISE(…) (triggers only in SQLite)syntax error
sql
SELECT '{"a": 1}' -> '$.a'

MIT License