SQLite Core & Scalar Functions

SQLite

Complete reference for SQLite core and scalar functions covering abs, coalesce, typeof, length, replace, nullif, and all other built-in scalar functions. Every function includes syntax, real SQL examples, and SQLite-specific quirk warnings. Updated for SQLite 3.52.

33 functions

What are SQLite Core & Scalar Functions?

SQLite core scalar functions are the foundational built-in functions available in every SQLite build. They operate on individual values and return a single result. Because SQLite uses dynamic typing (called type affinity), many core functions behave differently than their counterparts in PostgreSQL or MariaDB — for example, typeof() returns a storage class string rather than a SQL type name.

abs

SQLite 3.0.0 (original release)INTEGER or REAL

Returns the absolute value of the numeric argument X, returning NULL if X is NULL and 0.0 if X is a string or blob that cannot be converted to a numeric value.

Signature

abs(X)

Parameters

ParameterTypeDescription
XanyThe numeric value whose absolute value is to be returned.

Examples

Basic absolute value of a negative integer

sql
SELECT abs(-5);
5

Absolute value of a positive real

sql
SELECT abs(3.14);
3.14

Absolute value of a negative real

sql
SELECT abs(-3.14);
3.14

NULL propagates through abs()

sql
SELECT abs(NULL);
NULL

Non-numeric strings return 0.0

sql
SELECT abs('not a number');
0.0
Anti-PatternUsing abs() in a WHERE clause instead of BETWEEN

Writing WHERE abs(price - target) < 10 forces SQLite to compute abs() for every row, preventing any index on the price column from being used. This causes a full table scan even when a perfectly good index exists.

✓ Instead: Use a range predicate: WHERE price BETWEEN target - 10 AND target + 10 so the query planner can use an index on price.

Passing the minimum 64-bit integer -9223372036854775808 to abs() throws an integer overflow error because there is no positive 64-bit equivalent. The random() function deliberately avoids generating this value so its output can always be safely passed to abs().

SQLite Note

In PostgreSQL, abs() raises an error for numeric overflow too, but the overflow boundary differs by type. In SQLite, the only dangerous value is the single 64-bit minimum integer -9223372036854775808; passing a non-numeric string returns 0.0 instead of an error, unlike PostgreSQL which raises a cast error.

changes

SQLite 3.0.0 (original release)INTEGER

Returns the number of database rows changed, inserted, or deleted by the most recently completed INSERT, DELETE, or UPDATE statement, exclusive of changes in lower-level triggers.

Signature

changes()

Examples

Counts rows affected by the last INSERT

sql
INSERT INTO t(x) VALUES (1),(2),(3);
SELECT changes();
3

Counts rows matched and updated

sql
UPDATE t SET x = x + 1 WHERE x < 3;
SELECT changes();
2

Counts rows deleted

sql
DELETE FROM t WHERE x = 1;
SELECT changes();
1

Returns 0 if no rows existed to delete

sql
DELETE FROM t;
SELECT changes();
0

Returns 0 at the start of a new connection

sql
SELECT changes();
0
Anti-PatternIgnoring changes() after DELETE or UPDATE to verify affected rows

After a DELETE or UPDATE, developers often skip calling changes() and assume the operation succeeded on the expected rows. When a WHERE clause has a typo or a bound parameter is NULL, zero rows are affected with no error raised — the bug is completely silent.

✓ Instead: Always call changes() immediately after a mutating statement and check that the count matches your expectation before committing.

changes() only counts rows modified by the outermost statement, not by any triggers that statement fires. If you need to include trigger-induced changes, use total_changes() instead.

SQLite Note

PostgreSQL uses GET DIAGNOSTICS ROW_COUNT or the libpq PQcmdTuples() API to retrieve affected row counts — there is no equivalent scalar SQL function. SQLite's changes() is a first-class scalar function callable anywhere in a query.

char

SQLite 3.0.0 (original release)TEXT

Returns a string composed of characters having the Unicode code point values of the integers X1 through XN, respectively.

Signature

char(X1,X2,...,XN)

Parameters

ParameterTypeDescription
X1,X2,...,XNINTEGEROne or more integer Unicode code point values to convert into characters.

Examples

Single ASCII character from code point

sql
SELECT char(65);
A

Multiple code points form a string

sql
SELECT char(72, 101, 108, 108, 111);
Hello

Unicode character outside the ASCII range

sql
SELECT char(9829);

Emoji from a hexadecimal code point literal

sql
SELECT char(0x1F600);
😀

Verify UTF-8 byte output for ASCII code points

sql
SELECT hex(char(65, 66, 67));
414243
Anti-PatternBuilding multi-character strings by concatenating char() calls in a loop

Calling char() inside a loop and assembling a string character by character with the || operator is inefficient and fragile — each concatenation creates a new string object, and the intent is obscured by the boilerplate.

✓ Instead: If you need to assemble a string from a set of code points stored in a table, use group_concat(char(codepoint)) in a single aggregate query.

char() is the inverse of unicode(). It accepts any number of arguments and is useful for injecting special characters such as tabs (char(9)), newlines (char(10)), or non-ASCII glyphs into string expressions without needing escape sequences.

SQLite Note

PostgreSQL uses chr(N) (single argument only) for the same purpose. SQLite's char() is variadic and can produce a multi-character string in one call, whereas PostgreSQL chr() always returns a single character.

coalesce

SQLite 3.0.0 (original release)any

Returns a copy of its first non-NULL argument, or NULL if all arguments are NULL; requires at least 2 arguments.

Signature

coalesce(X,Y,...)

Parameters

ParameterTypeDescription
X,Y,...anyTwo or more expressions to evaluate in order; the first non-NULL value is returned.

Examples

Returns the first non-NULL value

sql
SELECT coalesce(NULL, 42);
42

Skips multiple NULLs to find a value

sql
SELECT coalesce(NULL, NULL, 'fallback');
fallback

Returns NULL when all arguments are NULL

sql
SELECT coalesce(NULL, NULL, NULL);
NULL

Typical use: column fallback chain in a query

sql
SELECT coalesce(price, list_price, 0.0) FROM products;
(first non-null price or 0.0)

coalesce(X,Y) is equivalent to ifnull(X,Y) for two args

sql
SELECT coalesce(NULL, 1) = ifnull(NULL, 1);
1
Anti-PatternUsing coalesce() to silently hide NULL data bugs

Wrapping a column in coalesce(column, 0) or coalesce(column, '') masks NULLs in query results without fixing why the NULLs exist in the first place. Downstream aggregations then operate on invented values, producing subtly wrong totals and averages that are hard to debug.

✓ Instead: Fix the root cause by adding a NOT NULL constraint with a DEFAULT at the schema level, reserving coalesce() for the rare case where NULL genuinely means 'use this fallback'.

SQLite evaluates coalesce() arguments left to right and stops as soon as it finds a non-NULL value, so expensive subqueries placed later in the argument list are skipped when an earlier argument is non-NULL.

SQLite Note

The behaviour and signature of coalesce() are the same in SQLite and PostgreSQL — both require at least 2 arguments and return the first non-NULL value. However, PostgreSQL also offers the COALESCE expression as part of standard SQL syntax with identical semantics.

glob

SQLite 3.0.0 (original release)INTEGER

Returns 1 if string Y matches glob pattern X using case-sensitive matching, equivalent to the expression 'Y GLOB X' but with the arguments reversed.

Signature

glob(X,Y)

Parameters

ParameterTypeDescription
XTEXTThe glob pattern to match against (uses * for any sequence and ? for any single character).
YTEXTThe string to test against the pattern.

Examples

Pattern matches the filename

sql
SELECT glob('*.txt', 'readme.txt');
1

Pattern does not match

sql
SELECT glob('*.txt', 'readme.md');
0

Character class in glob pattern

sql
SELECT glob('*[Ss]QLite*', 'SQLite3');
1

? matches exactly one character; 'my' is only two

sql
SELECT glob('???.db', 'my.db');
0

Use glob() as a WHERE predicate

sql
SELECT name FROM files WHERE glob('*.json', name);
(rows where name ends in .json)
Anti-PatternUsing GLOB when case-insensitive matching is needed

Unlike LIKE, the GLOB operator is always case-sensitive in SQLite — GLOB 'A*' will never match the string 'apple'. Developers migrating from other databases or mixing GLOB with LIKE often miss this, producing queries that silently return zero rows.

✓ Instead: Use LIKE for case-insensitive pattern matching, or normalize both sides with upper()/lower() if you specifically need GLOB's wildcard semantics.

In the GLOB operator you write 'Y GLOB X', but in the glob() function the order is glob(X, Y) — pattern first, string second. The function form exists so you can override the GLOB operator by replacing glob() with sqlite3_create_function().

SQLite Note

PostgreSQL has no built-in glob() function; it uses LIKE or SIMILAR TO for pattern matching, or the ~ operator with POSIX regular expressions. SQLite's GLOB is always case-sensitive, whereas LIKE is case-insensitive for ASCII letters by default.

See also:liketypeof

iif

SQLite 3.32.0 (2020-05-22); two-argument form and if() alias in 3.48.0; N-argument form in 3.49.0any

Evaluates pairs of Boolean/value arguments and returns the value associated with the first true Boolean; if no Boolean is true, returns the last argument (odd count) or NULL (even count).

Signatures

iif(B1,V1,...)
if(B1,V1,...)

Parameters

ParameterTypeDescription
B1,V1,...anyAlternating Boolean condition and value pairs; an optional trailing argument serves as the else-value.

Examples

Classic if-then-else with three arguments

sql
SELECT iif(1 > 0, 'yes', 'no');
yes

False condition returns the else branch

sql
SELECT iif(0, 'yes', 'no');
no

NULL Boolean is treated as false

sql
SELECT iif(NULL, 'yes', 'no');
no

Multi-condition form added in SQLite 3.49.0

sql
SELECT iif(score >= 90, 'A', score >= 80, 'B', score >= 70, 'C', 'F')
FROM grades;
(letter grade)

Two-argument form: returns x when true, else NULL (added in SQLite 3.48.0)

sql
SELECT if(x > 0, x) FROM t;
(x or NULL)
Anti-PatternNesting iif() three or more levels deep

Deeply nested iif(cond1, iif(cond2, iif(cond3, a, b), c), d) is functionally valid but nearly impossible to read, review, or modify without introducing a logic error in the nesting order. SQLite evaluates both branches eagerly in some contexts, so errors in any branch can surface unexpectedly.

✓ Instead: Replace multi-level nesting with CASE WHEN ... THEN ... WHEN ... THEN ... ELSE ... END, which scales cleanly to any number of conditions.

Value arguments that correspond to false Booleans are never evaluated, so expensive subqueries or functions in later branches incur no cost when an earlier condition is true. This makes iif() more efficient than equivalent CASE expressions in theory, though they compile to identical bytecode for the three-argument form.

SQLite Note

PostgreSQL has no iif() or if() function; the equivalent is a CASE expression: CASE WHEN B THEN V1 ELSE V2 END. SQLite's iif() is syntactic sugar for exactly that CASE expression and generates identical bytecode. The two-argument form and the if() alias were added in SQLite 3.48.0 (2025-01-14); support for more than three arguments was added in 3.49.0 (2025-02-06).

ifnull

SQLite 3.0.0 (original release)any

Returns a copy of its first non-NULL argument, or NULL if both arguments are NULL; equivalent to coalesce() with exactly two arguments.

Signature

ifnull(X,Y)

Parameters

ParameterTypeDescription
XanyThe primary value; returned as-is if it is not NULL.
YanyThe fallback value returned when X is NULL.

Examples

Returns the fallback when X is NULL

sql
SELECT ifnull(NULL, 'default');
default

Returns X when X is not NULL

sql
SELECT ifnull('value', 'default');
value

Returns NULL when both arguments are NULL

sql
SELECT ifnull(NULL, NULL);
NULL

Replace NULLs with empty string in a column

sql
SELECT ifnull(middle_name, '') FROM persons;
(middle name or empty string)

Column-level NULL substitution

sql
SELECT ifnull(price, list_price) FROM products;
(price or list_price)
Anti-PatternReaching for ifnull() when more than two fallback values are needed

ifnull(a, b) only accepts exactly two arguments. Developers sometimes write nested ifnull(ifnull(a, b), c) to handle a chain of fallbacks, which becomes unreadable quickly and is easy to get wrong when the nesting order matters.

✓ Instead: Use coalesce(a, b, c, ...) which accepts any number of arguments and returns the first non-NULL, making the intent immediately clear.

ifnull(X,Y) is exactly equivalent to coalesce(X,Y). Use ifnull() when you have exactly two operands for clarity; switch to coalesce() when you need a chain of three or more fallback values.

SQLite Note

PostgreSQL uses COALESCE(X,Y) for the same purpose and has no ifnull() function. SQLite supports both ifnull() and coalesce() with identical semantics. MySQL also has IFNULL(), so code using ifnull() is not portable to PostgreSQL without substitution.

last_insert_rowid

SQLite 3.0.0 (original release)INTEGER

Returns the ROWID of the last row inserted from the current database connection.

Signature

last_insert_rowid()

Examples

Returns the rowid of the just-inserted row

sql
INSERT INTO t(name) VALUES ('Alice');
SELECT last_insert_rowid();
1

Multi-row INSERT: returns the rowid of the last row

sql
INSERT INTO t(name) VALUES ('Bob'), ('Carol');
SELECT last_insert_rowid();
3

Returns 0 when no INSERT has been performed on this connection

sql
SELECT last_insert_rowid();
0

Works with explicit INTEGER PRIMARY KEY (alias for rowid)

sql
CREATE TABLE log(id INTEGER PRIMARY KEY, msg TEXT);
INSERT INTO log(msg) VALUES ('event');
SELECT last_insert_rowid();
1

Value is not reset by ROLLBACK

sql
BEGIN;
INSERT INTO t(name) VALUES ('Dave');
SELECT last_insert_rowid();
ROLLBACK;
(rowid of Dave, even after rollback)
Anti-PatternRelying on last_insert_rowid() after multiple statements in a transaction

last_insert_rowid() returns the rowid of the most recent successful INSERT on the current database connection. If any INSERT — including a trigger-fired INSERT — runs between your target insert and your call to last_insert_rowid(), the value you get back will be wrong.

✓ Instead: Call last_insert_rowid() immediately after the single INSERT you care about, before any other statement executes, or use RETURNING rowid in the INSERT statement itself (SQLite 3.35+).

last_insert_rowid() returns the rowid of the last successful INSERT on the connection, even if that INSERT was later rolled back. If you need the rowid of a committed row, read it before rolling back.

SQLite Note

PostgreSQL uses RETURNING id or the sequence function lastval() / currval() to retrieve auto-generated primary keys. SQLite has no RETURNING clause before version 3.35.0 (2021-03-12); last_insert_rowid() is the traditional way to retrieve the new rowid and is connection-scoped, not statement-scoped.

likelihood

SQLite 3.8.11 (2015-07-27)any

Returns its first argument X unchanged while providing the query planner with a hint that X is a Boolean true with probability Y (a floating-point constant between 0.0 and 1.0).

Signature

likelihood(X,Y)

Parameters

ParameterTypeDescription
XanyThe value or expression to return unchanged; typically a Boolean condition.
YREALA compile-time floating-point constant between 0.0 and 1.0 representing the probability that X is true.

Examples

Hints to the planner that x > 0 is true 90% of the time

sql
SELECT likelihood(x > 0, 0.9) FROM t;
(same as x > 0)

Optimizer hint on a WHERE clause predicate

sql
SELECT * FROM t WHERE likelihood(status = 'active', 0.95);
(active rows)

Pass-through: NULL in, NULL out

sql
SELECT likelihood(NULL, 0.5);
NULL

Equivalent to likely(1)

sql
SELECT likelihood(1, 0.9375);
1

Equivalent to unlikely(0)

sql
SELECT likelihood(0, 0.0625);
0
Anti-PatternUsing likelihood() with inaccurate probability values to force a query plan

Passing a probability to likelihood() that does not reflect reality — for example, likelihood(status = 'active', 0.01) when 90% of rows are active — misleads the query planner into choosing a worse plan. SQLite trusts the hint unconditionally and will pick a full table scan or bad join order as a result.

✓ Instead: Only use likelihood() when you have measured the actual selectivity of the expression; for most cases let the query planner use its own statistics or run ANALYZE to refresh them.

likelihood() is a no-op at runtime — the code generator removes it entirely from the bytecode. It exists solely to carry a probability annotation to the query planner. Use likely(X) and unlikely(X) as convenient shorthands for likelihood(X,0.9375) and likelihood(X,0.0625).

SQLite Note

PostgreSQL has no likelihood() function. The closest equivalent is the statistics stored by ANALYZE and adjustable via ALTER TABLE ... ALTER COLUMN ... SET STATISTICS, but there is no inline SQL-level probability hint function. SQLite's likelihood() has zero runtime overhead because it is compiled away.

likely

SQLite 3.8.11 (2015-07-27)any

Returns X unchanged and hints to the query planner that X is a Boolean value that is usually true; equivalent to likelihood(X, 0.9375).

Signature

likely(X)

Parameters

ParameterTypeDescription
XanyThe value or Boolean expression to return; the planner is told it is true about 93.75% of the time.

Examples

Tell the planner that most rows are active

sql
SELECT * FROM t WHERE likely(status = 'active');
(active rows)

Pass-through for a constant true value

sql
SELECT likely(1);
1

NULL passes through unchanged

sql
SELECT likely(NULL);
NULL

Hint that positive values are the common case

sql
SELECT likely(x > 0) FROM nums;
(same as x > 0)

Demonstrates equivalence to likelihood(X, 0.9375)

sql
SELECT likely(col) = likelihood(col, 0.9375)
FROM t LIMIT 1;
1
Anti-PatternApplying likely() to multiple conditions hoping to speed up the entire query

Wrapping several WHERE conditions in likely() at once adds noise that confuses the query planner without providing any benefit. When every condition is marked likely, the hints cancel each other out and the planner ignores them.

✓ Instead: Use likely() sparingly — only on the single condition that is genuinely true for the vast majority of rows — and rely on ANALYZE-updated statistics for everything else.

Misapplying likely() on a predicate that is actually rarely true can degrade query performance. Only use it when ANALYZE cannot capture selectivity, such as on functions or expressions over non-indexed columns.

SQLite Note

PostgreSQL has no likely() function. SQLite's likely() is a no-op at runtime — it is compiled away and incurs zero CPU overhead during query execution.

load_extension

SQLite 3.3.6 (2006-06-19)NULL

Loads an SQLite extension from the shared library file named X using entry point Y (or the default entry point if Y is omitted), returning NULL on success and raising an exception on failure.

Signatures

load_extension(X)
load_extension(X,Y)

Parameters

ParameterTypeDescription
XTEXTPath to the shared library (.so / .dll / .dylib) to load.
YTEXTOptional entry point function name in the shared library; defaults to a name derived from the library filename.

Examples

Load extension using the default entry point

sql
SELECT load_extension('./myext.so');
NULL

Load extension with a specific entry point

sql
SELECT load_extension('./myext.so', 'my_init');
NULL

Load a system extension

sql
SELECT load_extension('/usr/lib/sqlite3/pcre.so');
NULL

Extension name can be a URI

sql
SELECT load_extension(':memory:', 'sqlite3_series_init');
NULL

Extension loading must be enabled before this call works

sql
-- Enable extension loading first (C API or CLI):
-- sqlite3_enable_load_extension(db, 1);
SELECT load_extension('./ext.so');
NULL
Anti-PatternLeaving extension loading permanently enabled in production connections

Extension loading is disabled by default for security reasons. Calling load_extension() on a connection where it has not been explicitly enabled raises an error at runtime. Applications that leave extension loading enabled in production expose a local code execution vector if users can influence the path argument.

✓ Instead: Enable extensions only on trusted internal connections immediately before loading, then disable the capability again with sqlite3_enable_load_extension(db, 0) to limit the attack surface.

Extension loading is disabled by default for security reasons. It must be enabled via sqlite3_enable_load_extension() in the C API, the .load dot-command in the CLI, or a similar mechanism in your language binding. An extension that tries to modify or delete existing SQL functions must be loaded via the C API instead.

SQLite Note

PostgreSQL uses CREATE EXTENSION to install server-side extensions from a registry; there is no dynamic runtime loading function. SQLite's load_extension() loads shared libraries at runtime from the filesystem, which is a fundamentally different — and more flexible but less sandboxed — mechanism.

⚙ Availability: Disabled by default; requires sqlite3_enable_load_extension() to be called first (or SQLITE_LOAD_EXTENSION compile-time flag).

max

SQLite 3.0.0 (original release)any

Returns the argument with the maximum value from two or more arguments, returning NULL if any argument is NULL; operates as an aggregate function when given a single argument.

Signature

max(X,Y,...)

Parameters

ParameterTypeDescription
X,Y,...anyTwo or more values to compare; the greatest value is returned.

Examples

Maximum of three integers

sql
SELECT max(1, 2, 3);
3

Maximum of real values

sql
SELECT max(3.14, 2.72, 1.41);
3.14

String comparison uses BINARY collation

sql
SELECT max('banana', 'apple', 'cherry');
cherry

Any NULL argument causes the result to be NULL

sql
SELECT max(10, NULL);
NULL

Row-level max across columns (scalar form)

sql
SELECT max(a, b, c) FROM t;
(row-wise maximum)
Anti-PatternUsing scalar max(a, b) in a loop to find the maximum across rows

The scalar two-argument max(a, b) compares two expressions within the same row. Developers sometimes use it in subqueries or application loops to find the maximum across rows, forcing multiple round-trips when a single aggregate MAX() over the full result set would be faster and clearer.

✓ Instead: Use aggregate MAX(column) in a single SELECT to find the maximum value across rows; reserve the scalar max(a, b) form only for comparing two expressions within the same row.

max() with two or more arguments is the scalar greatest() function. max() with a single argument is the aggregate MAX(). PostgreSQL names these separately: greatest() for the scalar form and max() only for aggregation. In SQLite, both share the same name but differ by argument count.

SQLite Note

PostgreSQL separates greatest(X,Y,...) (scalar) from max(X) (aggregate). SQLite overloads the name max(): one argument triggers aggregate mode, two or more arguments trigger scalar mode. Unlike PostgreSQL's greatest(), SQLite's scalar max() returns NULL if any argument is NULL, whereas PostgreSQL's greatest() skips NULLs.

min

SQLite 3.0.0 (original release)any

Returns the argument with the minimum value from two or more arguments; operates as an aggregate function when given a single argument.

Signature

min(X,Y,...)

Parameters

ParameterTypeDescription
X,Y,...anyTwo or more values to compare; the smallest value is returned.

Examples

Minimum of four integers

sql
SELECT min(5, 3, 8, 1);
1

Minimum of real values

sql
SELECT min(3.14, 2.72, 1.41);
1.41

Lexicographic minimum with BINARY collation

sql
SELECT min('banana', 'apple', 'cherry');
apple

NULL in any argument propagates NULL out

sql
SELECT min(a, NULL);
NULL

Row-level minimum across two columns

sql
SELECT min(start_date, end_date) FROM events;
(earlier of the two dates per row)
Anti-PatternNesting scalar min() calls to find the minimum of three or more values

The scalar min(a, b) in SQLite accepts exactly two arguments, so finding the minimum of three values requires nesting: min(a, min(b, c)). This is error-prone and the syntax is visually identical to aggregate MIN(), making the code confusing to readers.

✓ Instead: For more than two values, use a VALUES clause and aggregate MIN(): SELECT MIN(v) FROM (VALUES (a),(b),(c)) t(v), which is clear and scales to any number of candidates.

SQLite's scalar min() returns NULL if any argument is NULL. PostgreSQL's least() ignores NULLs and returns the minimum of the non-NULL arguments. Wrap arguments in ifnull() if you need PostgreSQL-style NULL-skipping behaviour.

SQLite Note

PostgreSQL names the scalar form least(X,Y,...) and the aggregate form min(X). SQLite uses min() for both, disambiguated by argument count. PostgreSQL's least() skips NULLs; SQLite's scalar min() does not — any NULL argument returns NULL.

nullif

SQLite 3.0.0 (original release)any

Returns its first argument if the two arguments are different, or NULL if they are equal.

Signature

nullif(X,Y)

Parameters

ParameterTypeDescription
XanyThe value to return when X and Y are not equal.
YanyThe value to compare against X; if equal to X, NULL is returned.

Examples

Arguments differ, so X is returned

sql
SELECT nullif(5, 3);
5

Arguments are equal, so NULL is returned

sql
SELECT nullif(5, 5);
NULL

Useful for converting empty strings to NULL

sql
SELECT nullif('', '');
NULL

Classic use: avoid division by zero

sql
SELECT 10 / nullif(divisor, 0) FROM t;
(10/divisor or NULL)

Replace a sentinel value with NULL

sql
SELECT nullif(status, 'active') FROM accounts;
(NULL for active, status otherwise)
Anti-PatternConfusing nullif(a, b) with coalesce(a, b)

nullif(a, b) returns NULL when a equals b, and returns a otherwise — the opposite of what many developers expect. It is frequently confused with coalesce(a, b) which returns the first non-NULL value. Using nullif when coalesce was intended silently replaces matching values with NULL instead of providing a fallback.

✓ Instead: Use nullif() only for the specific purpose of converting a sentinel value (like 0 or '') to NULL so that aggregate functions will skip it; use coalesce() when you want a default fallback for NULLs.

COALESCE returns a value when it finds a non-NULL; nullif() does the reverse — it returns NULL when the arguments are equal. The classic safe-division pattern is 10 / nullif(denominator, 0), which yields NULL instead of a divide-by-zero error.

SQLite Note

nullif() behaves identically in SQLite and PostgreSQL. Both return NULL when the two arguments are equal and X otherwise. The function uses the same collation resolution rules as other binary comparison functions in SQLite.

quote

SQLite 3.0.0 (original release)TEXT

Returns the text of an SQL literal representing the value of X, with strings surrounded by single-quotes (interior quotes escaped) and BLOBs encoded as hexadecimal X'...' literals.

Signature

quote(X)

Parameters

ParameterTypeDescription
XanyThe value to be rendered as a safe SQL literal string.

Examples

String value wrapped in single quotes

sql
SELECT quote('hello');
'hello'

Interior single quotes are escaped by doubling

sql
SELECT quote('it''s');
'it''s'

Integer literals need no quoting

sql
SELECT quote(42);
42

Real literals need no quoting

sql
SELECT quote(3.14);
3.14

BLOB is rendered as a hex literal

sql
SELECT quote(x'DEADBEEF');
X'DEADBEEF'
Anti-PatternUsing quote() to format values for display in the UI

quote() returns SQL-literal representations: strings are single-quoted with internal quotes escaped, blobs are prefixed with X''. These formats are correct for embedding values back into SQL strings but look wrong and confusing when shown to end users in reports or interfaces.

✓ Instead: Use quote() exclusively for generating SQL text (e.g., for export scripts or dynamic SQL); use plain string formatting or CAST for human-readable display output.

quote() is used internally by the .dump CLI command to produce INSERT statements that correctly re-insert all data types, including BLOBs and strings with special characters. Use unistr_quote() instead if you also need control characters (U+0001–U+001F) to be escaped.

SQLite Note

PostgreSQL uses the quote_literal() and quote_ident() functions for similar escaping tasks. SQLite's quote() handles all scalar storage classes in one function and encodes BLOBs as X'...' hex literals, whereas PostgreSQL's quote_literal() only handles text and uses $ quoting for BYTEA differently.

random

SQLite 3.0.0 (original release)INTEGER

Returns a pseudo-random integer between -9223372036854775807 and +9223372036854775807.

Signature

random()

Examples

Example: a random 64-bit signed integer

sql
SELECT random();
-3842234817352819438

Random integer in the range 0–99

sql
SELECT abs(random()) % 100;
73

Random integer in a user-defined range

sql
SELECT abs(random()) % (max_val - min_val + 1) + min_val
FROM (SELECT 10 AS min_val, 20 AS max_val);
14

Random sample from a table

sql
SELECT * FROM t ORDER BY random() LIMIT 5;
(5 randomly ordered rows)

Normalize to a float in [0.0, 1.0]

sql
SELECT CAST(abs(random()) AS REAL) / 9223372036854775807.0;
0.4827...
Anti-PatternCalling random() in a loop to generate a sequence of random values

Executing SELECT random() in a loop from application code generates one random number per round-trip, making the code slow and its intent unclear. Each call is also independent, offering no guarantee of uniqueness across rows.

✓ Instead: Use ORDER BY random() in a single query to shuffle rows, or use randomblob(N) to generate a bulk random byte sequence in one call.

Unlike many languages where random() returns a float in [0.0, 1.0), SQLite's random() returns a 64-bit signed integer. Divide by 9223372036854775807.0 and take the absolute value to obtain a uniform float in [0.0, 1.0]. The PRNG has used Chacha20 since SQLite 3.40.0.

SQLite Note

PostgreSQL's random() returns a double precision float in [0.0, 1.0). SQLite's random() returns a 64-bit signed integer in [-9223372036854775807, +9223372036854775807]. The two functions have completely different return ranges and types, so code using random() is not directly portable between the two databases.

See also:randomblobabs

randomblob

SQLite 3.3.8 (2006-09-23)BLOB

Returns an N-byte BLOB containing pseudo-random bytes; if N is less than 1, a 1-byte random blob is returned.

Signature

randomblob(N)

Parameters

ParameterTypeDescription
NINTEGERThe number of random bytes to generate; values less than 1 produce a 1-byte blob.

Examples

4 random bytes shown as uppercase hex

sql
SELECT hex(randomblob(4));
A3F201BC

16-byte UUID-like identifier in lowercase hex

sql
SELECT lower(hex(randomblob(16)));
a3f201bc...

Verify the blob is exactly N bytes

sql
SELECT length(randomblob(32));
32

N < 1 produces a 1-byte blob

sql
SELECT hex(randomblob(0));
(2 hex chars)

Generate a random token for a new session

sql
INSERT INTO tokens(token) VALUES (lower(hex(randomblob(16))));
(insert with random 32-char hex token)
Anti-PatternStoring randomblob() output directly in a TEXT column without hex encoding

randomblob(16) produces a raw binary BLOB. Storing it directly in a TEXT column causes implicit coercion that can corrupt the value or produce unreadable data. Comparing two such BLOBs with = works at the byte level, but displaying or transmitting them as text is error-prone.

✓ Instead: Wrap the result in hex() or lower(hex()) to store it as a readable hexadecimal string, or use the hex-formatted UUID pattern: lower(hex(randomblob(4)))||'-'||... for RFC 4122 style UUIDs.

The SQLite documentation itself suggests hex(randomblob(16)) or lower(hex(randomblob(16))) as a simple way to generate a globally unique 128-bit identifier. For a proper UUID v4 format, use the uuid extension available in the CLI and many SQLite builds.

SQLite Note

PostgreSQL provides gen_random_bytes(N) from the pgcrypto extension and gen_random_uuid() for UUID generation. SQLite has no built-in UUID function in the core, but randomblob(16) combined with hex() provides a functionally equivalent random identifier. PostgreSQL returns BYTEA; SQLite returns BLOB.

round

SQLite 3.0.0 (original release)REAL

Returns the floating-point value X rounded to Y digits to the right of the decimal point; if Y is omitted or negative, it defaults to 0.

Signatures

round(X)
round(X,Y)

Parameters

ParameterTypeDescription
XREALThe number to be rounded.
YINTEGEROptional number of decimal places; defaults to 0 if omitted or negative.

Examples

Round to zero decimal places

sql
SELECT round(3.14159);
3.0

Round to two decimal places

sql
SELECT round(3.14159, 2);
3.14

Half-integer rounds away from zero

sql
SELECT round(3.5);
4.0

Rounds to 3 (away from zero, not banker's rounding)

sql
SELECT round(2.5);
3.0

Negative Y treated as 0; does not round to hundreds place

sql
SELECT round(12345.678, -2);
12346.0
Anti-PatternExpecting round() to return an INTEGER

round(2.5) returns 3.0 in SQLite, not the integer 3. Code that then inserts this into an INTEGER column or compares it with = to an integer constant works by accident due to type affinity coercion, but explicit CAST checks or strict-mode tables will see the value as REAL and behave unexpectedly.

✓ Instead: Apply CAST(round(x) AS INTEGER) explicitly when you need a true integer result, and be aware that SQLite uses 'round half away from zero' rather than the banker's rounding used by some other languages.

Unlike PostgreSQL where round() preserves the numeric type (returning INTEGER for round(3) and NUMERIC for round(3.5, 0)), SQLite's round() always returns a REAL value. The result of round(3) is 3.0, not 3. Cast to INTEGER explicitly if you need an integer result.

SQLite Note

PostgreSQL's round(X) returns a value of the same numeric type as X, so round(3.5) returns 4 as a NUMERIC, not 4.0 as a REAL. SQLite's round() always returns REAL. Additionally, PostgreSQL supports round(X, Y) with negative Y to round to the left of the decimal point; SQLite treats negative Y as 0 (rounds to whole number only).

See also:abssign

sign

SQLite 3.35.0 (2021-03-12)INTEGER

Returns -1, 0, or +1 if the numeric argument X is negative, zero, or positive respectively; returns NULL if X is NULL, a BLOB, or a string that cannot be losslessly converted to a number.

Signature

sign(X)

Parameters

ParameterTypeDescription
XanyA numeric value or expression whose sign is to be determined.

Examples

Negative number returns -1

sql
SELECT sign(-42);
-1

Zero returns 0

sql
SELECT sign(0);
0

Positive number returns 1

sql
SELECT sign(3.14);
1

NULL propagates

sql
SELECT sign(NULL);
NULL

Non-numeric string returns NULL

sql
SELECT sign('not a number');
NULL
Anti-PatternUsing sign() for NULL-safe equality comparisons instead of IS

Some developers use sign(a - b) = 0 as a NULL-safe equality check, but if either a or b is NULL, sign() returns NULL, which is falsy — so the comparison silently excludes NULL-containing rows rather than treating them as equal to each other.

✓ Instead: Use the IS operator (a IS b) for NULL-safe equality in SQLite; it returns 1 when both sides are NULL, and 0 when only one is, without any arithmetic gymnastics.

sign('3') returns 1 because '3' can be losslessly converted to the integer 3. However sign('3.5abc') returns NULL because that string cannot be losslessly converted. This differs from abs(), which returns 0.0 for any non-convertible string rather than NULL.

SQLite Note

PostgreSQL has a sign() function with the same semantics for numeric types. The key SQLite difference is that sign() returns NULL for strings that cannot be losslessly converted to a number, whereas PostgreSQL raises a type error. SQLite's sign() was added in version 3.35.0 together with the math functions.

See also:absround

soundex

SQLite 3.0.0 (original release, but compile-time only)TEXT

Returns a string that is the Soundex encoding of string X; returns '?000' if the argument is NULL or contains no ASCII alphabetic characters.

Signature

soundex(X)

Parameters

ParameterTypeDescription
XTEXTThe string whose Soundex phonetic code is to be computed.

Examples

Soundex code for 'Robert'

sql
SELECT soundex('Robert');
R163

'Robert' and 'Rupert' share the same Soundex code

sql
SELECT soundex('Rupert');
R163

Common surname example

sql
SELECT soundex('Smith');
S530

Empty string returns the default code

sql
SELECT soundex('');
?000

NULL also returns the default code

sql
SELECT soundex(NULL);
?000
Anti-PatternTreating SOUNDEX codes as language-independent phonetic matching

The soundex() function implements the original Soundex algorithm designed specifically for English surnames of European origin. Applying it to names from Arabic, Chinese, Hindi, or other non-Latin scripts produces meaningless or identical codes, giving false positives and missing true matches.

✓ Instead: For multilingual phonetic matching, load the ICU or unicode61 tokenizer extension, or implement language-specific normalization in application code before storing names; reserve soundex() for legacy English-only name deduplication tasks.

soundex() is not compiled into SQLite by default. It is only available when the library is built with the -DSQLITE_SOUNDEX compile-time option. Check sqlite_compileoption_used('SOUNDEX') to determine if it is available in the current build.

SQLite Note

PostgreSQL offers soundex() via the fuzzystrmatch extension (CREATE EXTENSION fuzzystrmatch). In SQLite, soundex() is a compile-time option (SQLITE_SOUNDEX) built directly into the library rather than loaded as a separate extension. Both implement the classic American Soundex algorithm.

⚙ Availability: Only available when SQLite is compiled with -DSQLITE_SOUNDEX.

sqlite_compileoption_get

SQLite 3.7.3 (2010-10-08)TEXT

Returns the N-th compile-time option used to build SQLite as a string, or NULL if N is out of range.

Signature

sqlite_compileoption_get(N)

Parameters

ParameterTypeDescription
NINTEGERZero-based index of the compile-time option to retrieve.

Examples

First compile-time option (example output)

sql
SELECT sqlite_compileoption_get(0);
COMPILER=gcc-14.2.0

Second compile-time option

sql
SELECT sqlite_compileoption_get(1);
DEFAULT_AUTOVACUUM

Out-of-range index returns NULL

sql
SELECT sqlite_compileoption_get(999);
NULL

List all compile-time options using a recursive CTE

sql
WITH RECURSIVE opts(n,o) AS (
  SELECT 0, sqlite_compileoption_get(0)
  UNION ALL
  SELECT n+1, sqlite_compileoption_get(n+1)
  FROM opts WHERE o IS NOT NULL
)
SELECT o FROM opts WHERE o IS NOT NULL;
(all compile-time options)

Equivalent pragma for listing all compile options

sql
PRAGMA compile_options;
(table of all options)
Anti-PatternIterating sqlite_compileoption_get() with a hardcoded upper bound

The number of compile-time options varies across SQLite versions and builds. Using a fixed loop limit like FOR i IN 0..100 risks missing options in a feature-rich build or wasting iterations on an empty return once the list is exhausted — sqlite_compileoption_get() returns NULL for out-of-range indices, but the exact count is not exposed directly.

✓ Instead: Loop until sqlite_compileoption_get(i) returns NULL, or query the pragma_compile_options virtual table with SELECT * FROM pragma_compile_options for a cleaner, set-based approach.

PRAGMA compile_options is usually easier to use than iterating sqlite_compileoption_get(N) manually. The function form is useful when you need to access options programmatically in a subquery or CTE.

SQLite Note

PostgreSQL has no equivalent function; compile-time options are embedded in the server binary and surfaced via pg_config or the pg_config() function. SQLite's compile-time options directly affect which features are available at runtime and are queryable through both a function and a pragma.

sqlite_compileoption_used

SQLite 3.7.3 (2010-10-08)INTEGER

Returns 1 if the compile-time option named X was used when building SQLite, or 0 if it was not.

Signature

sqlite_compileoption_used(X)

Parameters

ParameterTypeDescription
XTEXTThe name of the compile-time option to check (e.g., 'SOUNDEX', 'ENABLE_FTS5').

Examples

Returns 1 if SOUNDEX support is compiled in

sql
SELECT sqlite_compileoption_used('SOUNDEX');
1

Returns 0 if JSON support was not omitted

sql
SELECT sqlite_compileoption_used('OMIT_JSON');
0

Check if FTS5 full-text search is available

sql
SELECT sqlite_compileoption_used('ENABLE_FTS5');
1

Unknown options return 0, not an error

sql
SELECT sqlite_compileoption_used('NONEXISTENT_OPTION');
0

Guard optional feature use with a capability check

sql
SELECT iif(sqlite_compileoption_used('ENABLE_OFFSET_SQL_FUNC'),
  sqlite_offset(col), NULL) FROM t;
(offset or NULL)
Anti-PatternUsing sqlite_compileoption_used() at runtime to gate production feature paths

Checking compile options at runtime to decide whether to use a feature (e.g., FTS5 or JSON1) ties business logic to build configuration. If the library is replaced or recompiled without that option, the feature silently disappears with no schema or migration guard.

✓ Instead: Test for feature availability once at application startup, assert the required options are present, and fail fast with a clear error message rather than silently degrading at runtime.

Wrap calls to optional functions such as soundex() or sqlite_offset() inside an iif(sqlite_compileoption_used('SOUNDEX'), ..., NULL) to write code that degrades gracefully on builds that omit the feature.

SQLite Note

PostgreSQL has no equivalent single-function capability check. PostgreSQL features are controlled at extension installation time (CREATE EXTENSION) rather than compile time. In SQLite, many features are baked in at compile time and cannot be added at runtime, making this function important for writing portable SQLite code.

sqlite_offset

SQLite 3.28.0 (2019-04-16)INTEGER

Returns the byte offset in the database file for the beginning of the record from which the value of column X would be read, or NULL if X is not a column in an ordinary table.

Signature

sqlite_offset(X)

Parameters

ParameterTypeDescription
XanyA reference to a table column; the function returns the on-disk byte offset of that column's record.

Examples

Byte offset of the first row's name column record

sql
SELECT sqlite_offset(name) FROM users LIMIT 1;
4096

Offset of a specific row's record

sql
SELECT sqlite_offset(rowid) FROM t WHERE id = 42;
8192

Not a column reference — returns NULL

sql
SELECT sqlite_offset(1 + 1);
NULL

Show the storage offset for every row's name field

sql
SELECT name, sqlite_offset(name) FROM t;
(name, offset pairs)

Safe invocation guarded by compile-option check

sql
SELECT iif(sqlite_compileoption_used('ENABLE_OFFSET_SQL_FUNC'),
  sqlite_offset(col), NULL) FROM t LIMIT 1;
(offset or NULL)
Anti-PatternUsing sqlite_offset() on a column sourced from a view or subquery

sqlite_offset(X) returns the byte offset of column X within the raw database file, but it only works when X is a direct column reference from a real base table in the current query. Applying it to a column sourced from a view, subquery, or expression silently returns NULL, which looks like a valid 'no offset' result.

✓ Instead: Use sqlite_offset() only in simple SELECT statements that directly reference a real table column without any intervening view or subquery layer, and always verify the result is non-NULL before using it for blob I/O operations.

sqlite_offset() is primarily a debugging and low-level tool. Its main practical use is to locate a row's storage position before opening it with the sqlite3_blob_open() C API for incremental reading or writing of large BLOB values without loading them fully into memory.

SQLite Note

PostgreSQL has no equivalent function. This is a SQLite-specific introspection tool for the underlying B-tree file format. It only works when SQLite is compiled with -DSQLITE_ENABLE_OFFSET_SQL_FUNC, which is not the default.

⚙ Availability: Only available when SQLite is compiled with -DSQLITE_ENABLE_OFFSET_SQL_FUNC.

sqlite_source_id

SQLite 3.7.4 (2010-12-07)TEXT

Returns a string identifying the specific source code version used to build the SQLite library, consisting of the check-in date/time followed by the SHA3-256 hash of that check-in.

Signature

sqlite_source_id()

Examples

Date, time, and SHA3-256 hash of the source check-in

sql
SELECT sqlite_source_id();
2026-03-06 16:01:44 557aeb43869d3585...

Extract just the build date

sql
SELECT substr(sqlite_source_id(), 1, 10);
2026-03-06

Total length: 19 char date-time + 1 space + 64 char hash

sql
SELECT length(sqlite_source_id());
79

Deterministic: same value within a session

sql
SELECT sqlite_source_id() = sqlite_source_id();
1

Combine version and source ID for full build identification

sql
SELECT sqlite_version(), sqlite_source_id();
3.52.0 | 2026-03-06 16:01:44...
Anti-PatternParsing sqlite_source_id() output to extract the version number

sqlite_source_id() returns a string like '2024-01-01 00:00:00 abc123...' — a date plus a source hash. The format is not guaranteed to be stable across releases. Developers who split on spaces to grab the version number will get a date, not a version, and will break if the format ever changes.

✓ Instead: Use sqlite_version() to get the version string in the stable 'X.Y.Z' format, or check the sqlite_version pragma if you need a comparable integer.

While sqlite_version() gives the release version string like '3.52.0', sqlite_source_id() gives the SHA3-256 hash of the exact source tree used, which is useful for filing bug reports or verifying that a specific bug fix is included in the build.

SQLite Note

PostgreSQL uses version() to return a combined version and build info string, and has no separate source-ID function. SQLite keeps these separate: sqlite_version() for the human-readable release number and sqlite_source_id() for the exact source revision hash.

sqlite_version

SQLite 3.0.0 (original release)TEXT

Returns the version string for the running SQLite library, such as '3.52.0'.

Signature

sqlite_version()

Examples

Current library version

sql
SELECT sqlite_version();
3.52.0

Text comparison works for version ordering (same digit count)

sql
SELECT sqlite_version() >= '3.35.0';
1

Convert version to a comparable integer

sql
SELECT CAST(replace(sqlite_version(), '.', '') AS INTEGER);
3520

Show both version and source ID together

sql
SELECT sqlite_version(), sqlite_source_id();
3.52.0 | 2026-03-06...

Feature detection by version string

sql
SELECT iif(sqlite_version() >= '3.38.0', 'JSON built-in', 'JSON optional');
JSON built-in
Anti-PatternLexicographically comparing sqlite_version() strings to check for a minimum version

sqlite_version() returns a string like '3.45.1'. Comparing it with > or < gives wrong results: '3.9.0' > '3.45.1' is true under string comparison because '9' > '4', meaning old versions appear newer than they are.

✓ Instead: Convert the version to a comparable integer by splitting on '.' and computing major*1000000 + minor*1000 + patch, or use sqlite_compileoption_used() to test for the specific feature you actually need.

Comparing version strings lexicographically only works reliably when all components have the same number of digits. For robust feature detection, use sqlite_compileoption_used() to check specific capabilities rather than comparing version numbers.

SQLite Note

PostgreSQL uses version() which returns a longer string including the OS and compiler. SQLite's sqlite_version() returns only the version number (e.g. '3.52.0'). There is no PostgreSQL equivalent to SQLite's sqlite_source_id() for the exact source hash.

total_changes

SQLite 3.0.0 (original release)INTEGER

Returns the total number of row changes caused by INSERT, UPDATE, or DELETE statements since the current database connection was opened.

Signature

total_changes()

Examples

Zero at the start of a new connection

sql
SELECT total_changes();
0

Accumulates across statements

sql
INSERT INTO t VALUES (1),(2),(3);
SELECT total_changes();
3

Total includes all previous statements on the connection

sql
DELETE FROM t;
SELECT total_changes();
6

Compare per-statement and cumulative counts together

sql
SELECT changes(), total_changes();
(last stmt count, cumulative count)

total_changes() includes changes made by triggers

sql
CREATE TRIGGER log_changes AFTER INSERT ON t BEGIN
  -- trigger fires here
END;
INSERT INTO t VALUES (42);
SELECT total_changes();
7
Anti-PatternUsing total_changes() as a cross-connection audit counter

total_changes() counts all INSERT, UPDATE, and DELETE operations accumulated since the current database connection was opened. It is per-connection: changes made by other connections to the same database file are not reflected. Using it as a global audit counter in a multi-connection or WAL-mode setup produces systematically wrong counts.

✓ Instead: For cross-connection change tracking, use a trigger that writes to an audit table, or use the SQLite update hook API in your driver to capture every change on the specific connection you care about.

Unlike changes() which excludes lower-level trigger changes, total_changes() counts every row modification since the connection opened, including those caused by triggers. Reset by opening a new connection.

SQLite Note

PostgreSQL has no equivalent cumulative change-count function accessible as a scalar SQL expression. The PostgreSQL C API provides PQcmdTuples() for the most recent command only. SQLite's total_changes() is useful for progress monitoring and auditing within a long-lived connection.

typeof

SQLite 3.0.0 (original release)TEXT

Returns a string indicating the storage class of expression X: one of 'null', 'integer', 'real', 'text', or 'blob'.

Signature

typeof(X)

Parameters

ParameterTypeDescription
XanyThe expression whose storage class is to be determined.

Examples

The null storage class

sql
SELECT typeof(NULL);
null

Integer literal

sql
SELECT typeof(42);
integer

Real (floating-point) literal

sql
SELECT typeof(3.14);
real

Text string

sql
SELECT typeof('hello');
text

Binary BLOB literal

sql
SELECT typeof(x'DEADBEEF');
blob
Anti-PatternUsing typeof() for type-checking in application logic instead of enforcing schema constraints

Calling typeof(column) = 'integer' in a WHERE clause or application layer to filter out wrongly typed values treats a schema enforcement problem as a query-time workaround. Because SQLite uses dynamic typing, any column can hold any type, so typeof() checks become necessary everywhere if schema constraints are missing.

✓ Instead: Define columns with appropriate type affinity and add CHECK constraints at the schema level to reject badly typed inserts at write time, removing the need for typeof() guards in every SELECT.

typeof() returns one of exactly five values: 'null', 'integer', 'real', 'text', or 'blob'. These are storage classes, not declared column types. Because SQLite uses dynamic typing, a column declared as TEXT can store integers, and typeof() will return 'integer' for those rows.

SQLite Note

PostgreSQL uses pg_typeof(X) to return a data type name such as 'integer' or 'text'. SQLite's typeof() returns one of only five storage class names regardless of the column's declared type. This reflects SQLite's fundamental dynamic typing (type affinity) model, which is very different from PostgreSQL's strict static type system.

See also:quotecastiif

unhex

SQLite 3.41.0 (2023-02-21)BLOB

Returns a BLOB that is the decoding of hexadecimal string X, ignoring characters in Y if provided; returns NULL if X contains non-hex characters not in Y, or if hex digits are not paired.

Signatures

unhex(X)
unhex(X,Y)

Parameters

ParameterTypeDescription
XTEXTA hexadecimal string to decode into binary; digits may be upper or lower case.
YTEXTOptional string of separator characters to ignore when present between hex digit pairs (e.g., '-' for UUID notation).

Examples

Decode a pure hex string to BLOB

sql
SELECT unhex('48656C6C6F');
(BLOB: 'Hello' bytes)

The result is always a BLOB

sql
SELECT typeof(unhex('FF'));
blob

Cast the BLOB back to text

sql
SELECT cast(unhex('48656C6C6F') AS TEXT);
Hello

Decode a UUID string by ignoring hyphens

sql
SELECT unhex('550e8400-e29b-41d4-a716-446655440000', '-');
(16-byte UUID BLOB)

Non-hex characters with no Y argument cause NULL

sql
SELECT unhex('ZZZZ');
NULL
Anti-PatternPassing unhex() output directly into a TEXT context expecting a readable string

unhex('48656C6C6F') returns the raw binary bytes for 'Hello', not the ASCII string 'Hello'. Inserting the result into a TEXT column or concatenating it with || can produce garbled output because SQLite will store the blob bytes rather than interpreting them as UTF-8 text.

✓ Instead: If you want to decode a hex-encoded UTF-8 string, cast the result explicitly: CAST(unhex(hex_value) AS TEXT), and verify the source hex truly encodes valid UTF-8 before inserting into a text column.

The two-argument form unhex(uuid_string, '-') is ideal for converting UUID strings to compact 16-byte BLOBs for storage. The Y argument lists separator characters to silently skip, so hyphens between UUID groups are ignored without any prior string manipulation.

SQLite Note

PostgreSQL has no unhex() function; the equivalent is decode(string, 'hex') from the encode/decode functions, which returns BYTEA. SQLite's unhex() was added in version 3.41.0 (2023-02-21) and is therefore absent from older SQLite installations. The Y separator argument has no PostgreSQL equivalent.

unicode

SQLite 3.8.7 (2014-10-17)INTEGER

Returns the numeric Unicode code point of the first character of string X.

Signature

unicode(X)

Parameters

ParameterTypeDescription
XTEXTA string whose first character's Unicode code point is to be returned.

Examples

ASCII code point for uppercase A

sql
SELECT unicode('A');
65

Only the first character is examined

sql
SELECT unicode('Hello');
72

Unicode code point for the heart symbol

sql
SELECT unicode('♥');
9829

Code point for a 4-byte UTF-8 emoji

sql
SELECT unicode('😀');
128512

Advance a character by incrementing its code point

sql
SELECT char(unicode('a') + 1);
b
Anti-PatternUsing unicode() to validate that an entire string contains valid Unicode

unicode(X) returns the numeric code point of only the first character of X. Passing a multi-character string does not validate the rest of the characters — it silently ignores everything after the first code point. Developers sometimes use it as a Unicode validity check, but it only ever inspects one character.

✓ Instead: To check an entire string for valid Unicode content, use a regular expression check or application-layer validation; use unicode() only when you specifically need the integer code point of the first character.

unicode(X) and char(N) are inverses: unicode(char(N)) = N for any valid code point, and char(unicode(X)) = the first character of X. Use them together to perform arithmetic on characters.

SQLite Note

PostgreSQL uses ascii(X) to return the code point of the first character (limited to Latin-1 range in older versions) and unicode is available as ascii() for multi-byte characters in modern versions. SQLite's unicode() works correctly with all Unicode code points including supplementary characters above U+FFFF.

See also:charunistrhex

unistr

SQLite 3.50.0 (2025-05-29)TEXT

Interprets backslash Unicode escape sequences in string X and returns a new string with those escapes converted into the actual Unicode characters they represent.

Signature

unistr(X)

Parameters

ParameterTypeDescription
XTEXTA string potentially containing backslash-encoded Unicode escapes (\XXXX, \+XXXXXX, \uXXXX, \UXXXXXXXX); \\ is a literal backslash.

Examples

\uXXXX escape for Unicode BMP character

sql
SELECT unistr('\u0041');
A

Escape within a string

sql
SELECT unistr('Hello\u0020World');
Hello World

\UXXXXXXXX for supplementary characters

sql
SELECT unistr('\U0001F600');
😀

Double backslash produces a literal backslash

sql
SELECT unistr('back\\slash');
back\slash

\XXXX form (4 hex digits without u prefix)

sql
SELECT unistr('\2665');
Anti-PatternPassing raw user-supplied input directly to unistr() without sanitization

unistr() processes \uXXXX and \UXXXXXXXX Unicode escape sequences embedded in strings. If user-supplied input is passed directly to unistr() without sanitization, a malicious \u0000 null character or an invalid surrogate pair escape can produce unexpected behavior in downstream text handling or C string APIs.

✓ Instead: Validate and sanitize user input before passing it to unistr(), or use unistr() only on compile-time string literals and developer-controlled data, never on raw user input.

The SQLite CLI's .dump command uses unistr() to safely encode strings containing control characters (U+0001–U+001F) into portable SQL that can be re-executed without terminal rendering issues. unistr_quote() wraps this into a quoting function suitable for inclusion in SQL literals.

SQLite Note

unistr() was added in SQLite 3.50.0 (2025-05-29) specifically to match the unistr() function in PostgreSQL, SQL Server, and Oracle. The PostgreSQL version accepts the same \uXXXX and \UXXXXXXXX escape sequences. Code using unistr() should be largely portable between SQLite 3.50.0+ and PostgreSQL.

unistr_quote

SQLite 3.50.0 (2025-05-29)TEXT

Like quote(X) but also escapes control characters (U+0001–U+001F) and backslashes using JSON-style backslash escapes, wrapping the result in unistr(...) when escaping was needed.

Signature

unistr_quote(X)

Parameters

ParameterTypeDescription
XanyThe value to serialize as a safe SQL literal, with control characters additionally escaped.

Examples

Plain string: identical to quote()

sql
SELECT unistr_quote('hello');
'hello'

Integer: identical to quote()

sql
SELECT unistr_quote(42);
42

Newline (U+000A) is escaped as \n

sql
SELECT unistr_quote('line1' || char(10) || 'line2');
unistr('line1\nline2')

Control character U+0001 is escaped

sql
SELECT unistr_quote(char(1));
unistr('\u0001')

BLOB: identical to quote()

sql
SELECT unistr_quote(x'DEADBEEF');
X'DEADBEEF'
Anti-PatternConfusing unistr_quote() output with quote() output and mixing them in SQL

unistr_quote() escapes non-ASCII control characters as \uXXXX sequences suitable for round-tripping through unistr(), whereas quote() produces standard SQL single-quoted literals with escaped apostrophes. The two formats are not interchangeable: pasting unistr_quote() output into a SQL statement without wrapping it in unistr() will store the escape sequences as literal text.

✓ Instead: Use unistr_quote() only when you intend the value to be decoded by unistr() later; use quote() when you need a SQL-safe literal for dynamic statement construction.

unistr_quote() is preferred over quote() when generating SQL scripts that may be displayed on terminals that interpret ANSI escape codes, because embedded control characters (like ESC, U+001B) would otherwise be rendered as terminal commands. The .dump CLI command uses unistr_quote() for this reason.

SQLite Note

PostgreSQL has no unistr_quote() function. The closest PostgreSQL equivalent is quote_literal() combined with regexp_replace() to escape control characters. SQLite's unistr_quote() was added in 3.50.0 alongside unistr() to support safe serialization of strings containing control characters in .dump output.

unlikely

SQLite 3.8.11 (2015-07-27)any

Returns X unchanged and hints to the query planner that X is a Boolean value that is usually not true; equivalent to likelihood(X, 0.0625).

Signature

unlikely(X)

Parameters

ParameterTypeDescription
XanyThe value or Boolean expression to return; the planner is told it is true only about 6.25% of the time.

Examples

Hint that error rows are rare

sql
SELECT * FROM t WHERE unlikely(error_flag = 1);
(rows with error)

Pass-through for a constant false value

sql
SELECT unlikely(0);
0

NULL passes through unchanged

sql
SELECT unlikely(NULL);
NULL

Hint that negative values are uncommon

sql
SELECT unlikely(x < 0) FROM nums;
(same as x < 0)

Demonstrates equivalence to likelihood(X, 0.0625)

sql
SELECT unlikely(x) = likelihood(x, 0.0625)
FROM t LIMIT 1;
1
Anti-PatternApplying unlikely() to a condition that actually filters out the majority of rows

unlikely(X) is a hint that expression X is false for most rows. If you apply it to a condition that is actually true for the majority of rows, the query planner will choose a strategy optimized for a highly selective filter — such as an index scan — when a full table scan would actually be faster.

✓ Instead: Use unlikely() only after profiling confirms the condition is rarely true; for conditions that eliminate most rows, use likely() or no hint at all and let ANALYZE provide accurate statistics.

unlikely() is best applied to predicates that filter out rare exception rows — for example, error conditions, soft-deleted records, or administrative flags. It encourages the planner to scan first and filter later rather than seeking by index on a very selective predicate.

SQLite Note

PostgreSQL has no unlikely() function. SQLite's unlikely() is a no-op at runtime with zero CPU overhead; it exists solely to pass a selectivity hint to the query planner during compilation.

zeroblob

SQLite 3.3.8 (2006-09-23)BLOB

Returns a BLOB consisting of N bytes of 0x00, managed efficiently by SQLite for reserving space that will later be written using incremental BLOB I/O.

Signature

zeroblob(N)

Parameters

ParameterTypeDescription
NINTEGERThe number of zero bytes to include in the returned BLOB.

Examples

Verify the blob is exactly N bytes

sql
SELECT length(zeroblob(100));
100

Result storage class is blob

sql
SELECT typeof(zeroblob(10));
blob

Four zero bytes in hex

sql
SELECT hex(zeroblob(4));
00000000

Reserve 1 MB of space for later incremental write

sql
INSERT INTO files(data) VALUES (zeroblob(1048576));
SELECT last_insert_rowid();
(rowid)

Zero-length blob when N = 0

sql
SELECT zeroblob(0);
(empty BLOB)
Anti-PatternUsing zeroblob() to pre-allocate space and then immediately overwriting it in the same statement

The purpose of zeroblob(N) is to reserve a blob of N bytes in the database so that incremental I/O can fill it later via the sqlite3_blob_open / sqlite3_blob_write C API or the equivalent driver method. Writing zeroblob() and then immediately replacing the value in the same transaction negates the benefit and wastes write I/O.

✓ Instead: Use zeroblob(N) only when you plan to write the blob incrementally using the incremental blob I/O API; for blobs you already have in memory, insert the blob value directly in the INSERT statement.

SQLite stores zeroblob() data very compactly in the file format — it does not write N actual zero bytes. The zero bytes are materialized on read. The intended workflow is: INSERT with zeroblob(N) to reserve space, capture the rowid, then write content incrementally using sqlite3_blob_open() and sqlite3_blob_write() in the C API.

SQLite Note

PostgreSQL has no zeroblob() function. The PostgreSQL equivalent for pre-allocating large object space is the lo_create() / lo_open() large object API, which is fundamentally different. In PostgreSQL, BYTEA columns store actual bytes in-place. SQLite's zeroblob() is efficient precisely because of SQLite's on-disk format treating zero-byte BLOBs as a special case.