Built-in Functions
Built-in Functions
Section titled “Built-in Functions”Comprehensive reference of all built-in functions, organized by category.
String Functions
Section titled “String Functions”UPPER / LOWER
Section titled “UPPER / LOWER”UPPER(string TEXT) → TEXT — Converts all characters to upper case.
LOWER(string TEXT) → TEXT — Converts all characters to lower case.
SELECT UPPER('hello'); -- 'HELLO'SELECT LOWER('WORLD'); -- 'world'LENGTH / CHAR_LENGTH
Section titled “LENGTH / CHAR_LENGTH”LENGTH(string TEXT) → INT — Returns the number of characters in the string.
SELECT LENGTH('hello'); -- 5SELECT LENGTH(''); -- 0LEFT / RIGHT
Section titled “LEFT / RIGHT”LEFT(string TEXT, n INT) → TEXT — Returns the first n characters. If n is negative, returns all but the last |n| characters.
RIGHT(string TEXT, n INT) → TEXT — Returns the last n characters.
SELECT LEFT('PostgreSQL', 4); -- 'Post'SELECT RIGHT('PostgreSQL', 3); -- 'SQL'SELECT LEFT('hello', -2); -- 'hel'TRIM / BTRIM / LTRIM / RTRIM
Section titled “TRIM / BTRIM / LTRIM / RTRIM”TRIM([LEADING|TRAILING|BOTH] [chars TEXT] FROM string TEXT) → TEXT — Removes characters (default: spaces) from the start, end, or both.
BTRIM(string TEXT [, chars TEXT]) → TEXT — Removes chars from both ends.
LTRIM(string TEXT [, chars TEXT]) → TEXT — Removes chars from the left.
RTRIM(string TEXT [, chars TEXT]) → TEXT — Removes chars from the right.
SELECT TRIM(' hello '); -- 'hello'SELECT BTRIM('xxhelloxx', 'x'); -- 'hello'SELECT LTRIM('000123', '0'); -- '123'LPAD / RPAD
Section titled “LPAD / RPAD”LPAD(string TEXT, length INT [, fill TEXT]) → TEXT — Left-pads string to length using fill (default: space).
RPAD(string TEXT, length INT [, fill TEXT]) → TEXT — Right-pads string to length using fill.
SELECT LPAD('42', 5, '0'); -- '00042'SELECT RPAD('hi', 5, '.'); -- 'hi...'REPEAT
Section titled “REPEAT”REPEAT(string TEXT, number INT) → TEXT — Repeats string the given number of times.
SELECT REPEAT('ab', 3); -- 'ababab'REVERSE
Section titled “REVERSE”REVERSE(string TEXT) → TEXT — Reverses the characters of a string.
SELECT REVERSE('hello'); -- 'olleh'INITCAP
Section titled “INITCAP”INITCAP(string TEXT) → TEXT — Converts the first letter of each word to upper case and the rest to lower case.
SELECT INITCAP('hello world'); -- 'Hello World'ASCII / CHR
Section titled “ASCII / CHR”ASCII(string TEXT) → INT — Returns the ASCII code of the first character.
CHR(code INT) → TEXT — Returns the character with the given ASCII code.
SELECT ASCII('A'); -- 65SELECT CHR(65); -- 'A'STRPOS / POSITION
Section titled “STRPOS / POSITION”STRPOS(string TEXT, substring TEXT) → INT — Returns the position of the first occurrence of substring (1-based; 0 if not found).
POSITION(substring TEXT IN string TEXT) → INT — SQL standard form of STRPOS.
SELECT STRPOS('hello world', 'world'); -- 7SELECT POSITION('lo' IN 'hello'); -- 4SPLIT_PART
Section titled “SPLIT_PART”SPLIT_PART(string TEXT, delimiter TEXT, field INT) → TEXT — Splits string on delimiter and returns the nth field (1-based).
SELECT SPLIT_PART('a,b,c', ',', 2); -- 'b'SELECT SPLIT_PART('2024-03-15', '-', 1); -- '2024'TRANSLATE
Section titled “TRANSLATE”TRANSLATE(string TEXT, from TEXT, to TEXT) → TEXT — Replaces characters in from with corresponding characters in to. If to is shorter, extra from characters are deleted.
SELECT TRANSLATE('hello', 'el', 'ip'); -- 'hippo'SELECT TRANSLATE('123-456', '-', ''); -- '123456'QUOTE_IDENT / QUOTE_LITERAL / QUOTE_NULLABLE
Section titled “QUOTE_IDENT / QUOTE_LITERAL / QUOTE_NULLABLE”QUOTE_IDENT(string TEXT) → TEXT — Returns string as a safely quoted SQL identifier (double-quotes where needed).
QUOTE_LITERAL(string TEXT) → TEXT — Returns string as a safely quoted SQL literal.
QUOTE_NULLABLE(value TEXT) → TEXT — Like QUOTE_LITERAL but returns NULL for NULL input.
SELECT QUOTE_IDENT('my table'); -- '"my table"'SELECT QUOTE_LITERAL('it''s'); -- '''it''''s'''SELECT QUOTE_NULLABLE(NULL); -- 'NULL'OVERLAY
Section titled “OVERLAY”OVERLAY(string TEXT PLACING replacement TEXT FROM start INT [FOR length INT]) → TEXT — Replaces a substring within string.
SELECT OVERLAY('hello world' PLACING 'DB9' FROM 7); -- 'hello DB9ld'SELECT OVERLAY('hello world' PLACING 'DB9' FROM 7 FOR 5); -- 'hello DB9'CONCAT
Section titled “CONCAT”CONCAT CONCAT(val1 TEXT, val2 TEXT, ...)→ TEXT Concatenates all arguments. NULL arguments are silently ignored (unlike the || operator, which returns NULL if any operand is NULL).
SELECT CONCAT('DB', '9'); -- 'DB9'SELECT CONCAT('Hello', NULL, ' World'); -- 'Hello World'CONCAT_WS
Section titled “CONCAT_WS”CONCAT_WS CONCAT_WS(separator TEXT, val1 TEXT, val2 TEXT, ...)→ TEXT Concatenates arguments with a separator between each. The first argument is the separator. NULL values in the list are skipped.
SELECT CONCAT_WS(', ', 'Alice', 'Bob', 'Carol'); -- 'Alice, Bob, Carol'SELECT CONCAT_WS('-', '2024', '01', '15'); -- '2024-01-15'SUBSTRING
Section titled “SUBSTRING”SUBSTRING SUBSTRING(string TEXT, start INT [, length INT])→ TEXT Extracts a substring starting at position start (1-based). Also supports SQL standard form: SUBSTRING(string FROM start FOR length). Supports regex extraction: SUBSTRING(string FROM pattern).
SELECT SUBSTRING('PostgreSQL', 1, 4); -- 'Post'SELECT SUBSTRING('PostgreSQL' FROM 5); -- 'greSQL'SELECT SUBSTRING('foo@bar.com' FROM '@(.*)'); -- 'bar.com'REPLACE
Section titled “REPLACE”REPLACE REPLACE(string TEXT, from TEXT, to TEXT)→ TEXT Replaces all occurrences of substring from in string with to.
SELECT REPLACE('Hello World', 'World', 'DB9'); -- 'Hello DB9'FORMAT
Section titled “FORMAT”FORMAT FORMAT(formatstr TEXT [, args ANY, ...])→ TEXT Formats a string using printf-style specifiers: %s (string), %I (quoted identifier), %L (quoted literal), %% (literal %). Useful for safely building dynamic SQL.
SELECT FORMAT('Hello, %s!', 'World'); -- 'Hello, World!'SELECT FORMAT('SELECT * FROM %I WHERE id = %L', 'users', 42); -- 'SELECT * FROM users WHERE id = ''42'''CONCAT
Section titled “CONCAT”CONCAT CONCAT(val1 TEXT, val2 TEXT, ...)→ TEXT Concatenates all arguments. NULL arguments are silently ignored (unlike the || operator, which returns NULL if any operand is NULL).
SELECT CONCAT('DB', '9'); -- 'DB9'SELECT CONCAT('Hello', NULL, ' World'); -- 'Hello World'SELECT CONCAT(42, ' items'); -- '42 items'CONCAT_WS
Section titled “CONCAT_WS”CONCAT_WS CONCAT_WS(separator TEXT, val1 TEXT, val2 TEXT, ...)→ TEXT Concatenates arguments with a separator between each. The first argument is the separator. NULL values in the list are skipped.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
separator | TEXT | Yes | — | String placed between each non-NULL value |
val1, val2, ... | TEXT | Yes | — | Values to join; NULLs are skipped |
SELECT CONCAT_WS(', ', 'Alice', 'Bob', 'Carol'); -- 'Alice, Bob, Carol'SELECT CONCAT_WS('-', '2024', '01', '15'); -- '2024-01-15'SELECT CONCAT_WS(', ', 'Alice', NULL, 'Carol'); -- 'Alice, Carol'SUBSTRING
Section titled “SUBSTRING”SUBSTRING SUBSTRING(string TEXT, start INT [, length INT])→ TEXT Extracts a substring starting at position start (1-based). Also supports the SQL standard form: SUBSTRING(string FROM start FOR length). Supports regex extraction: SUBSTRING(string FROM pattern).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
string | TEXT | Yes | — | Source string |
start | INT | Yes | — | Starting position (1-based) |
length | INT | No | to end | Number of characters to extract |
SELECT SUBSTRING('PostgreSQL', 1, 4); -- 'Post'SELECT SUBSTRING('PostgreSQL' FROM 5); -- 'greSQL'SELECT SUBSTRING('foo@bar.com' FROM '@(.*)'); -- 'bar.com'REPLACE
Section titled “REPLACE”REPLACE REPLACE(string TEXT, from TEXT, to TEXT)→ TEXT Replaces all occurrences of substring from in string with to.
SELECT REPLACE('Hello World', 'World', 'DB9'); -- 'Hello DB9'SELECT REPLACE('aabbcc', 'bb', 'XX'); -- 'aaXXcc'FORMAT
Section titled “FORMAT”FORMAT FORMAT(formatstr TEXT [, args ANY, ...])→ TEXT Formats a string using printf-style format specifiers. Supports %s (string), %I (quoted identifier), %L (quoted literal), and %% (literal %). Particularly useful for safely building dynamic SQL.
SELECT FORMAT('Hello, %s!', 'World');-- 'Hello, World!'
SELECT FORMAT('SELECT * FROM %I WHERE id = %L', 'users', 42);-- 'SELECT * FROM users WHERE id = ''42'''Mathematical Functions
Section titled “Mathematical Functions”ABS(x NUMERIC) → NUMERIC — Absolute value.
SELECT ABS(-42); -- 42CEIL / CEILING / FLOOR
Section titled “CEIL / CEILING / FLOOR”CEIL(x NUMERIC) → NUMERIC — Nearest integer greater than or equal to x. CEILING is an alias.
FLOOR(x NUMERIC) → NUMERIC — Nearest integer less than or equal to x.
SELECT CEIL(4.2); -- 5SELECT FLOOR(4.8); -- 4ROUND / TRUNC
Section titled “ROUND / TRUNC”ROUND(x NUMERIC [, s INT]) → NUMERIC — Rounds to s decimal places (default 0).
TRUNC(x NUMERIC [, s INT]) → NUMERIC — Truncates to s decimal places (default 0).
SELECT ROUND(4.567, 2); -- 4.57SELECT TRUNC(4.567, 2); -- 4.56SELECT ROUND(4.5); -- 5SQRT / CBRT
Section titled “SQRT / CBRT”SQRT(x NUMERIC) → NUMERIC — Square root.
CBRT(x DOUBLE PRECISION) → DOUBLE PRECISION — Cube root.
SELECT SQRT(16); -- 4SELECT CBRT(27); -- 3POWER / EXP / LN / LOG
Section titled “POWER / EXP / LN / LOG”POWER(base NUMERIC, exp NUMERIC) → NUMERIC — Raises base to the power of exp.
EXP(x NUMERIC) → NUMERIC — Exponential (e^x).
LN(x NUMERIC) → NUMERIC — Natural logarithm.
LOG(b NUMERIC, x NUMERIC) → NUMERIC — Logarithm of x to base b. LOG(x) = log base 10.
SELECT POWER(2, 10); -- 1024SELECT EXP(1); -- 2.718281828...SELECT LN(EXP(1)); -- 1SELECT LOG(100); -- 2SELECT LOG(2, 8); -- 3MOD(y NUMERIC, x NUMERIC) → NUMERIC — Remainder of y / x.
SELECT MOD(10, 3); -- 1SIGN(x NUMERIC) → NUMERIC — Returns -1, 0, or 1 based on the sign of x.
SELECT SIGN(-5); -- -1SELECT SIGN(0); -- 0SELECT SIGN(5); -- 1PI / DEGREES / RADIANS
Section titled “PI / DEGREES / RADIANS”PI() → DOUBLE PRECISION — Returns π (3.14159…).
DEGREES(x DOUBLE PRECISION) → DOUBLE PRECISION — Converts radians to degrees.
RADIANS(x DOUBLE PRECISION) → DOUBLE PRECISION — Converts degrees to radians.
SELECT PI(); -- 3.14159265358979SELECT DEGREES(PI()); -- 180SELECT RADIANS(180); -- 3.14159265358979Trigonometric Functions
Section titled “Trigonometric Functions”SIN(x), COS(x), TAN(x) — Sine, cosine, tangent (argument in radians).
SELECT SIN(PI() / 2); -- 1SELECT COS(0); -- 1RANDOM
Section titled “RANDOM”RANDOM() → DOUBLE PRECISION — Returns a random value in [0.0, 1.0).
SELECT RANDOM(); -- e.g. 0.37428...SELECT FLOOR(RANDOM() * 100)::int AS rand; -- random int 0–99HASHTEXT
Section titled “HASHTEXT”HASHTEXT(string TEXT) → INT — Returns an integer hash of the string. Useful for sharding or bucketing.
SELECT HASHTEXT('hello') % 10 AS shard; -- consistent bucket 0–9Date/Time Functions
Section titled “Date/Time Functions”DATE_TRUNC
Section titled “DATE_TRUNC”DATE_TRUNC DATE_TRUNC(field TEXT, source TIMESTAMP|TIMESTAMPTZ|INTERVAL [, timezone TEXT])→ TIMESTAMP|TIMESTAMPTZ|INTERVAL Truncates a timestamp or interval to the specified precision. Supported fields: microseconds, milliseconds, second, minute, hour, day, week, month, quarter, year, decade, century, millennium.
SELECT DATE_TRUNC('month', '2024-03-15 14:30'::timestamp); -- 2024-03-01 00:00:00SELECT DATE_TRUNC('hour', NOW()); -- current hour
SELECT DATE_TRUNC('day', created_at) AS day, COUNT(*) AS nFROM logs GROUP BY 1 ORDER BY 1;EXTRACT / DATE_PART
Section titled “EXTRACT / DATE_PART”EXTRACT EXTRACT(field FROM source TIMESTAMP|TIMESTAMPTZ|INTERVAL|DATE)→ NUMERIC Extracts a numeric subfield. DATE_PART(field, source) is an equivalent functional form. Common fields: year, month, day, hour, minute, second, epoch, dow (0=Sun), doy, quarter, week.
SELECT EXTRACT(year FROM '2024-03-15'::date); -- 2024SELECT EXTRACT(epoch FROM INTERVAL '1 day'); -- 86400SELECT DATE_PART('dow', NOW()); -- day of week 0-6NOW / CURRENT_TIMESTAMP
Section titled “NOW / CURRENT_TIMESTAMP”NOW NOW()→ TIMESTAMPTZ Returns the current transaction start time. Within a transaction, NOW() always returns the same value. Use CLOCK_TIMESTAMP() for the actual wall-clock time.
SELECT NOW(); -- transaction start timeSELECT CURRENT_TIMESTAMP; -- alias for NOW()SELECT CLOCK_TIMESTAMP(); -- actual current time (changes mid-transaction)CURRENT_DATE
Section titled “CURRENT_DATE”CURRENT_DATE → DATE — Current date (no time component).
SELECT CURRENT_DATE; -- 2024-03-15AGE(timestamp1 TIMESTAMPTZ, timestamp2 TIMESTAMPTZ) → INTERVAL — Computes the difference between two timestamps as a symbolic interval.
AGE(timestamp TIMESTAMPTZ) → INTERVAL — Difference between NOW() and the argument.
SELECT AGE('2024-03-15'::date, '2020-01-01'::date);-- 4 years 2 mons 14 days
SELECT AGE(birth_date) AS age FROM users;-- Age of each userTO_CHAR
Section titled “TO_CHAR”TO_CHAR TO_CHAR(value TIMESTAMP|NUMERIC|INTERVAL, format TEXT)→ TEXT Formats a timestamp, number, or interval. Common patterns: YYYY MM DD HH24 MI SS MS.
SELECT TO_CHAR(NOW(), 'YYYY-MM-DD HH24:MI:SS'); -- '2024-03-15 14:30:00'SELECT TO_CHAR(1234.56, 'FM9999.99'); -- '1234.56'DATE_TRUNC
Section titled “DATE_TRUNC”DATE_TRUNC DATE_TRUNC(field TEXT, source TIMESTAMP|TIMESTAMPTZ|INTERVAL [, timezone TEXT])→ TIMESTAMP|TIMESTAMPTZ|INTERVAL Truncates a timestamp or interval to the specified precision. Returns the same type as the input. The optional timezone argument controls which timezone is used for truncation of TIMESTAMPTZ values.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
field | TEXT | Yes | — | Precision: microseconds, milliseconds, second, minute, hour, day, week, month, quarter, year, decade, century, millennium |
source | TIMESTAMP | TIMESTAMPTZ | INTERVAL | Yes | — | Value to truncate |
timezone | TEXT | No | session timezone | Timezone for TIMESTAMPTZ truncation (e.g. 'America/New_York') |
SELECT DATE_TRUNC('month', '2024-03-15 14:30:00'::timestamp);-- 2024-03-01 00:00:00
SELECT DATE_TRUNC('hour', NOW());-- e.g. 2024-03-15 14:00:00+00
-- Group events by daySELECT DATE_TRUNC('day', created_at) AS day, COUNT(*) AS eventsFROM logsGROUP BY 1ORDER BY 1;EXTRACT / DATE_PART
Section titled “EXTRACT / DATE_PART”EXTRACT EXTRACT(field FROM source TIMESTAMP|TIMESTAMPTZ|INTERVAL|DATE)→ NUMERIC Extracts a numeric subfield from a date/time value. DATE_PART(field, source) is an equivalent functional form. Returns a NUMERIC (not integer).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
field | TEXT | Yes | — | year, month, day, hour, minute, second, dow (0=Sun), doy, epoch, quarter, week, timezone, timezone_hour, timezone_minute |
source | TIMESTAMP | TIMESTAMPTZ | INTERVAL | DATE | Yes | — | Value to extract from |
SELECT EXTRACT(year FROM '2024-03-15'::date); -- 2024SELECT EXTRACT(month FROM NOW()); -- current month numberSELECT EXTRACT(epoch FROM INTERVAL '1 day'); -- 86400SELECT DATE_PART('dow', '2024-03-15'::date); -- 5 (Friday)NOW / CURRENT_TIMESTAMP
Section titled “NOW / CURRENT_TIMESTAMP”NOW NOW()→ TIMESTAMPTZ Returns the current transaction start time as TIMESTAMPTZ. Within a transaction, NOW() always returns the same value — the time the transaction began. Use CLOCK_TIMESTAMP() for the actual current wall-clock time that advances during a transaction.
SELECT NOW(); -- 2024-03-15 14:30:00.123456+00SELECT CURRENT_TIMESTAMP; -- same as NOW()SELECT CLOCK_TIMESTAMP(); -- actual wall-clock time (changes within transaction)TO_CHAR
Section titled “TO_CHAR”TO_CHAR TO_CHAR(value TIMESTAMP|NUMERIC|INTERVAL, format TEXT)→ TEXT Formats a timestamp, number, or interval as a string using a format template. Common patterns: YYYY (4-digit year), MM (month 01-12), DD (day 01-31), HH24 (hour 0-23), MI (minute), SS (second), MS (millisecond).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
value | TIMESTAMP | NUMERIC | INTERVAL | Yes | — | Value to format |
format | TEXT | Yes | — | Format template string |
SELECT TO_CHAR(NOW(), 'YYYY-MM-DD'); -- '2024-03-15'SELECT TO_CHAR(NOW(), 'HH24:MI:SS'); -- '14:30:00'SELECT TO_CHAR(NOW(), 'Day, DD Month YYYY'); -- 'Friday , 15 March 2024'SELECT TO_CHAR(1234567.89, '9,999,999.99'); -- '1,234,567.89'SELECT TO_CHAR(INTERVAL '2 hours 30 mins', 'HH24:MI'); -- '02:30'MAKE_INTERVAL
Section titled “MAKE_INTERVAL”PostgreSQL-compatible interval constructor. All parameters optional, default 0.
MAKE_INTERVAL(years, months, weeks, days, hours, mins, secs)
SELECT MAKE_INTERVAL(days => 10); -- 10 daysSELECT MAKE_INTERVAL(hours => 1, mins => 30); -- 01:30:00SELECT MAKE_INTERVAL(years => 1, months => 6); -- 1 year 6 monsSELECT MAKE_INTERVAL(weeks => 2, days => 3, secs => 1.5); -- 17 days 00:00:01.5Returns INTERVAL. Named-argument syntax (param => value) is supported and recommended.
TIMEZONE
Section titled “TIMEZONE”TIMEZONE(zone TEXT, timestamp TIMESTAMP) → TIMESTAMPTZ — Treat timestamp as being in zone and convert to TIMESTAMPTZ.
TIMEZONE(zone TEXT, timestamptz TIMESTAMPTZ) → TIMESTAMP — Convert TIMESTAMPTZ to local timestamp in zone.
SELECT TIMEZONE('America/New_York', NOW()); -- time in NY as local TIMESTAMPSELECT NOW() AT TIME ZONE 'America/New_York'; -- equivalent operator formAggregate Functions
Section titled “Aggregate Functions”COUNT(*) → BIGINT — Counts all rows including NULLs.
COUNT(expression) → BIGINT — Counts non-NULL values of expression.
COUNT(DISTINCT expression) → BIGINT — Counts distinct non-NULL values.
SELECT COUNT(*) FROM users;SELECT COUNT(email) FROM users; -- excludes NULL emailsSELECT COUNT(DISTINCT country) FROM users;SUM / AVG / MIN / MAX
Section titled “SUM / AVG / MIN / MAX”SUM(expression) — Sum of non-NULL values.
AVG(expression) — Average of non-NULL values.
MIN(expression) — Minimum non-NULL value.
MAX(expression) — Maximum non-NULL value.
SELECT SUM(amount), AVG(amount), MIN(amount), MAX(amount) FROM orders;STRING_AGG
Section titled “STRING_AGG”STRING_AGG STRING_AGG(expression TEXT, delimiter TEXT [ORDER BY sort_expression])→ TEXT Concatenates non-NULL string values with a delimiter. NULLs are skipped.
SELECT STRING_AGG(name, ', ' ORDER BY name) FROM users;-- 'Alice, Bob, Carol'ARRAY_AGG
Section titled “ARRAY_AGG”ARRAY_AGG ARRAY_AGG(expression ANY [ORDER BY sort_expression])→ ARRAY Collects values into an array. Supports ORDER BY. Use FILTER (WHERE expr IS NOT NULL) to exclude NULLs.
SELECT ARRAY_AGG(id ORDER BY id) FROM users; -- {1,2,3,4,5}BOOL_AND / BOOL_OR / EVERY
Section titled “BOOL_AND / BOOL_OR / EVERY”BOOL_AND(expression BOOLEAN) → BOOLEAN — True if all non-NULL values are true.
BOOL_OR(expression BOOLEAN) → BOOLEAN — True if any non-NULL value is true.
EVERY(expression BOOLEAN) → BOOLEAN — Alias for BOOL_AND.
SELECT BOOL_AND(active) FROM users; -- true only if all users are activeSELECT BOOL_OR(has_premium) FROM users; -- true if any user has premiumJSON_AGG / JSONB_AGG
Section titled “JSON_AGG / JSONB_AGG”JSON_AGG(expression) → JSON — Aggregates values into a JSON array, preserving NULL entries.
JSONB_AGG(expression) → JSONB — Same but returns JSONB.
SELECT JSONB_AGG(ROW_TO_JSON(u)) FROM users u;-- [{"id":1,"name":"Alice"}, {"id":2,"name":"Bob"}, ...]STRING_AGG
Section titled “STRING_AGG”STRING_AGG STRING_AGG(expression TEXT, delimiter TEXT [ORDER BY sort_expression])→ TEXT Concatenates non-NULL string values with a delimiter. Supports ORDER BY within the aggregate to control concatenation order. Returns NULL when no rows match.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
expression | TEXT | Yes | — | Value to aggregate (NULLs are skipped) |
delimiter | TEXT | Yes | — | Separator placed between values |
SELECT STRING_AGG(name, ', ')FROM users;-- 'Alice, Bob, Carol'
-- With ORDER BY for deterministic orderingSELECT STRING_AGG(name, ', ' ORDER BY name)FROM users;-- 'Alice, Bob, Carol'
-- Per-group tagsSELECT post_id, STRING_AGG(tag, ' | ' ORDER BY tag) AS tagsFROM post_tagsGROUP BY post_id;ARRAY_AGG
Section titled “ARRAY_AGG”ARRAY_AGG ARRAY_AGG(expression ANY [ORDER BY sort_expression])→ ARRAY Collects values into an array. NULLs are included by default — use FILTER (WHERE expr IS NOT NULL) to exclude them. Supports ORDER BY within the aggregate.
SELECT ARRAY_AGG(id ORDER BY id) FROM users;-- {1,2,3,4,5}
SELECT user_id, ARRAY_AGG(tag ORDER BY tag) AS tagsFROM user_tagsGROUP BY user_id;
-- Exclude NULLsSELECT ARRAY_AGG(email) FILTER (WHERE email IS NOT NULL) FROM users;Window Functions
Section titled “Window Functions”All aggregate functions can also be used as window functions with an OVER clause.
ROW_NUMBER
Section titled “ROW_NUMBER”ROW_NUMBER ROW_NUMBER() OVER ([PARTITION BY expr] ORDER BY expr)→ BIGINT Sequential integer from 1 within partition. No gaps — every row gets a unique number.
-- Most recent order per userSELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn FROM orders) t WHERE rn = 1;RANK / DENSE_RANK
Section titled “RANK / DENSE_RANK”RANK() OVER (...) — Rank within partition, with gaps for ties (1, 1, 3…).
DENSE_RANK() OVER (...) — Rank within partition, without gaps for ties (1, 1, 2…).
SELECT name, score, RANK() OVER (ORDER BY score DESC) AS rank, DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rankFROM leaderboard;NTILE(buckets INT) OVER ([PARTITION BY expr] ORDER BY expr) → INT — Divides rows into buckets number of approximately equal groups and assigns a bucket number to each row.
SELECT user_id, amount, NTILE(4) OVER (ORDER BY amount DESC) AS quartileFROM orders;PERCENT_RANK / CUME_DIST
Section titled “PERCENT_RANK / CUME_DIST”PERCENT_RANK() OVER (...) — Relative rank: (rank - 1) / (total rows - 1). Returns 0 to 1.
CUME_DIST() OVER (...) — Cumulative distribution: fraction of rows ≤ current row’s value. Returns (0, 1].
SELECT score, PERCENT_RANK() OVER (ORDER BY score) AS pct_rank, CUME_DIST() OVER (ORDER BY score) AS cume_distFROM test_results;LAG LAG(value ANY [, offset INT [, default ANY]]) OVER ([PARTITION BY expr] ORDER BY expr)→ same as value Returns the value from a row offset rows before the current row. Default offset is 1. Returns default (or NULL) if no such row exists.
SELECT date, revenue, LAG(revenue, 1, 0) OVER (ORDER BY date) AS prev_revenueFROM daily_sales;LEAD LEAD(value ANY [, offset INT [, default ANY]]) OVER ([PARTITION BY expr] ORDER BY expr)→ same as value Returns the value from a row offset rows after the current row. Mirror of LAG.
SELECT event_id, scheduled_at, LEAD(scheduled_at) OVER (ORDER BY scheduled_at) AS next_eventFROM events;FIRST_VALUE / LAST_VALUE / NTH_VALUE
Section titled “FIRST_VALUE / LAST_VALUE / NTH_VALUE”FIRST_VALUE(value) OVER (...) — Value at the first row of the window frame.
LAST_VALUE(value) OVER (...) — Value at the last row of the window frame.
NTH_VALUE(value, n INT) OVER (...) — Value at the nth row of the window frame (1-based).
SELECT user_id, amount, FIRST_VALUE(amount) OVER (PARTITION BY user_id ORDER BY created_at ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS first_amount, LAST_VALUE(amount) OVER (PARTITION BY user_id ORDER BY created_at ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING) AS last_amountFROM orders;ROW_NUMBER
Section titled “ROW_NUMBER”ROW_NUMBER ROW_NUMBER() OVER ([PARTITION BY expr] ORDER BY expr)→ BIGINT Assigns a sequential integer starting from 1 to each row within its window partition. Unlike RANK(), there are never gaps — every row gets a unique number within its partition.
-- Number rows per userSELECT id, user_id, created_at, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at) AS rnFROM orders;
-- Get the most recent order per userSELECT * FROM ( SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC) AS rn FROM orders) t WHERE rn = 1;LAG LAG(value ANY [, offset INT [, default ANY]]) OVER ([PARTITION BY expr] ORDER BY expr)→ same as value Returns the value from a row that is offset rows before the current row within the window partition. If no such row exists, returns default (or NULL if unspecified).
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
value | ANY | Yes | — | Expression to evaluate at the lagged row |
offset | INT | No | 1 | Number of rows back to look |
default | ANY | No | NULL | Value to return when the offset row does not exist |
-- Previous day's revenue and deltaSELECT date, revenue, LAG(revenue) OVER (ORDER BY date) AS prev_revenue, revenue - LAG(revenue, 1, 0) OVER (ORDER BY date) AS deltaFROM daily_sales;LEAD LEAD(value ANY [, offset INT [, default ANY]]) OVER ([PARTITION BY expr] ORDER BY expr)→ same as value Returns the value from a row that is offset rows after the current row within the window partition. Mirror of LAG — same parameters, looks forward instead of backward.
-- Next scheduled event timestampSELECT event_id, scheduled_at, LEAD(scheduled_at) OVER (ORDER BY scheduled_at) AS next_eventFROM events;FIRST_VALUE
Section titled “FIRST_VALUE”FIRST_VALUE FIRST_VALUE(value ANY) OVER ([PARTITION BY expr] ORDER BY expr [frame])→ same as value Returns the value evaluated at the first row of the window frame. The default frame is RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW — use ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING to always get the first row of the entire partition.
-- First order amount per user alongside each orderSELECT user_id, order_id, amount, FIRST_VALUE(amount) OVER ( PARTITION BY user_id ORDER BY created_at ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING ) AS first_order_amountFROM orders;JSON/JSONB Functions
Section titled “JSON/JSONB Functions”JSONB_SET
Section titled “JSONB_SET”JSONB_SET JSONB_SET(target JSONB, path TEXT[], new_value JSONB [, create_missing BOOLEAN])→ JSONB Returns target with the element at path replaced by new_value. If create_missing is true (default), creates missing path segments.
SELECT JSONB_SET('{"name":"Alice"}'::jsonb, '{email}', '"alice@example.com"', true);-- {"name": "Alice", "email": "alice@example.com"}
UPDATE users SET metadata = JSONB_SET(metadata, '{theme}', '"dark"') WHERE id = 1;JSONB_BUILD_OBJECT / JSONB_BUILD_ARRAY
Section titled “JSONB_BUILD_OBJECT / JSONB_BUILD_ARRAY”JSONB_BUILD_OBJECT JSONB_BUILD_OBJECT(key1 TEXT, value1 ANY [, key2, value2, ...])→ JSONB Builds a JSONB object from alternating key/value pairs.
JSONB_BUILD_ARRAY(val1 ANY, val2 ANY, ...) → JSONB — Builds a JSONB array from arguments.
SELECT JSONB_BUILD_OBJECT('id', 1, 'name', 'Alice'); -- {"id": 1, "name": "Alice"}SELECT JSONB_BUILD_ARRAY(1, 'two', true); -- [1, "two", true]JSONB_EXTRACT_PATH / JSONB_EXTRACT_PATH_TEXT
Section titled “JSONB_EXTRACT_PATH / JSONB_EXTRACT_PATH_TEXT”JSONB_EXTRACT_PATH(from_json JSONB, VARIADIC path_elem TEXT[]) → JSONB — Extracts a nested element as JSONB.
JSONB_EXTRACT_PATH_TEXT(from_json JSONB, VARIADIC path_elem TEXT[]) → TEXT — Extracts a nested element as TEXT.
SELECT JSONB_EXTRACT_PATH('{"a":{"b":1}}'::jsonb, 'a', 'b'); -- 1 (JSONB)SELECT JSONB_EXTRACT_PATH_TEXT('{"a":{"b":1}}'::jsonb, 'a', 'b'); -- '1' (TEXT)JSONB_ARRAY_ELEMENTS / JSONB_ARRAY_ELEMENTS_TEXT
Section titled “JSONB_ARRAY_ELEMENTS / JSONB_ARRAY_ELEMENTS_TEXT”JSONB_ARRAY_ELEMENTS(from_json JSONB) → SETOF JSONB — Expands a JSON array to a set of JSONB elements.
JSONB_ARRAY_ELEMENTS_TEXT(from_json JSONB) → SETOF TEXT — Expands a JSON array to a set of TEXT values.
SELECT * FROM JSONB_ARRAY_ELEMENTS('[1, "two", true]'::jsonb);-- 1 / "two" / true (as JSONB rows)
SELECT * FROM JSONB_ARRAY_ELEMENTS_TEXT('["a","b","c"]'::jsonb);-- a / b / c (as text rows)JSONB_EACH / JSONB_EACH_TEXT
Section titled “JSONB_EACH / JSONB_EACH_TEXT”JSONB_EACH JSONB_EACH(from_json JSONB)→ SETOF (key TEXT, value JSONB) Expands a JSON object into key/value rows. Use JSONB_EACH_TEXT to get both key and value as TEXT.
SELECT key, value FROM JSONB_EACH('{"a":1,"b":2}'::jsonb);SELECT key, value FROM JSONB_EACH_TEXT('{"a":"x","b":"y"}'::jsonb);JSONB_TYPEOF
Section titled “JSONB_TYPEOF”JSONB_TYPEOF(from_json JSONB) → TEXT — Returns the type of the top-level JSON value: object, array, string, number, boolean, null.
SELECT JSONB_TYPEOF('{"a":1}'::jsonb); -- 'object'SELECT JSONB_TYPEOF('[1,2,3]'::jsonb); -- 'array'SELECT JSONB_TYPEOF('42'::jsonb); -- 'number'JSONB_ARRAY_LENGTH
Section titled “JSONB_ARRAY_LENGTH”JSONB_ARRAY_LENGTH(from_json JSONB) → INT — Returns the number of elements in a JSON array.
SELECT JSONB_ARRAY_LENGTH('[1,2,3,4]'::jsonb); -- 4JSONB_EXISTS / JSONB_EXISTS_ANY / JSONB_EXISTS_ALL
Section titled “JSONB_EXISTS / JSONB_EXISTS_ANY / JSONB_EXISTS_ALL”JSONB_EXISTS(from_json JSONB, key TEXT) → BOOLEAN — True if the given key exists at the top level.
JSONB_EXISTS_ANY(from_json JSONB, keys TEXT[]) → BOOLEAN — True if any key from the array exists.
JSONB_EXISTS_ALL(from_json JSONB, keys TEXT[]) → BOOLEAN — True if all keys from the array exist.
SELECT JSONB_EXISTS('{"a":1,"b":2}'::jsonb, 'a'); -- trueSELECT JSONB_EXISTS_ANY('{"a":1}'::jsonb, ARRAY['a','c']); -- trueSELECT JSONB_EXISTS_ALL('{"a":1,"b":2}'::jsonb, ARRAY['a','b']); -- trueJSONB_OBJECT_KEYS
Section titled “JSONB_OBJECT_KEYS”JSONB_OBJECT_KEYS(from_json JSONB) → SETOF TEXT — Returns the set of top-level keys of the JSON object.
SELECT JSONB_OBJECT_KEYS('{"name":"Alice","age":30}'::jsonb);-- 'name' / 'age'JSONB_PRETTY
Section titled “JSONB_PRETTY”JSONB_PRETTY(from_json JSONB) → TEXT — Returns a human-readable, indented JSON string.
SELECT JSONB_PRETTY('{"a":1,"b":{"c":2}}'::jsonb);-- {-- "a": 1,-- "b": {-- "c": 2-- }-- }TO_JSON / TO_JSONB / ROW_TO_JSON
Section titled “TO_JSON / TO_JSONB / ROW_TO_JSON”TO_JSON(any) → JSON — Converts any SQL value to its JSON representation.
TO_JSONB(any) → JSONB — Same but returns JSONB.
ROW_TO_JSON(record [, pretty_bool]) → JSON — Converts a row to a JSON object.
SELECT TO_JSONB(ARRAY[1,2,3]); -- [1, 2, 3]SELECT ROW_TO_JSON(u) FROM users u LIMIT 1; -- {"id":1,"name":"Alice",...}JSON_BUILD_OBJECT / JSON_BUILD_ARRAY / JSON_OBJECT_KEYS / JSON_ARRAY_ELEMENTS / JSON_ARRAY_ELEMENTS_TEXT
Section titled “JSON_BUILD_OBJECT / JSON_BUILD_ARRAY / JSON_OBJECT_KEYS / JSON_ARRAY_ELEMENTS / JSON_ARRAY_ELEMENTS_TEXT”These are the non-JSONB variants. They preserve original JSON key order and are set-returning.
JSON_BUILD_OBJECT(...), JSON_BUILD_ARRAY(...) — Same as JSONB variants but return JSON.
JSON_OBJECT_KEYS(from_json JSON) → SETOF TEXT — Returns top-level keys.
JSON_ARRAY_ELEMENTS(from_json JSON) → SETOF JSON — Expands a JSON array.
JSON_ARRAY_ELEMENTS_TEXT(from_json JSON) → SETOF TEXT — Expands to text.
JSONB_SET
Section titled “JSONB_SET”JSONB_SET JSONB_SET(target JSONB, path TEXT[], new_value JSONB [, create_missing BOOLEAN])→ JSONB Returns target with the item at path replaced by new_value. If create_missing is true (the default) and a path segment does not exist, it is created. Use the #- operator to delete a path.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
target | JSONB | Yes | — | Source JSONB value to update |
path | TEXT[] | Yes | — | Path to the element, e.g. '{addr,city}' or '{0}' for array index |
new_value | JSONB | Yes | — | Replacement value (must be valid JSON) |
create_missing | BOOLEAN | No | true | If true, creates keys that do not exist along the path |
SELECT JSONB_SET('{"name":"Alice","age":30}'::jsonb, '{age}', '31');-- {"name": "Alice", "age": 31}
SELECT JSONB_SET('{"user":{"name":"Alice"}}'::jsonb, '{user,email}', '"alice@example.com"', true);-- {"user": {"name": "Alice", "email": "alice@example.com"}}
-- Update a column in placeUPDATE usersSET metadata = JSONB_SET(metadata, '{preferences,theme}', '"dark"')WHERE id = 1;JSONB_BUILD_OBJECT
Section titled “JSONB_BUILD_OBJECT”JSONB_BUILD_OBJECT JSONB_BUILD_OBJECT(key1 TEXT, value1 ANY [, key2, value2, ...])→ JSONB Builds a JSONB object from a list of alternating key/value pairs. Keys must be strings; values are converted to their JSON equivalents automatically.
SELECT JSONB_BUILD_OBJECT('name', 'Alice', 'age', 30);-- {"name": "Alice", "age": 30}
-- Build a response object from row dataSELECT JSONB_BUILD_OBJECT( 'id', id, 'name', name, 'email', email, 'created_at', created_at) AS user_jsonFROM users WHERE id = 1;JSONB_EXTRACT_PATH_TEXT
Section titled “JSONB_EXTRACT_PATH_TEXT”JSONB_EXTRACT_PATH_TEXT JSONB_EXTRACT_PATH_TEXT(from_json JSONB, VARIADIC path_elem TEXT[])→ TEXT Extracts a nested field as TEXT using a variadic path. Equivalent to the #>> operator. Returns NULL if the path doesn't exist. Use JSONB_EXTRACT_PATH (without _TEXT) to return JSONB instead.
SELECT JSONB_EXTRACT_PATH_TEXT('{"user":{"name":"Alice","city":"NYC"}}'::jsonb, 'user', 'city');-- 'NYC'
-- Equivalent operator formSELECT '{"user":{"name":"Alice"}}'::jsonb #>> '{user,name}';-- 'Alice'JSONB_ARRAY_ELEMENTS
Section titled “JSONB_ARRAY_ELEMENTS”JSONB_ARRAY_ELEMENTS JSONB_ARRAY_ELEMENTS(from_json JSONB)→ SETOF JSONB Expands a JSON array into a set of JSONB values, one row per element. Use JSONB_ARRAY_ELEMENTS_TEXT to get plain text values instead of JSONB.
SELECT value FROM JSONB_ARRAY_ELEMENTS('[1, 2, 3]'::jsonb);-- 1-- 2-- 3
-- Expand an array column for per-element filteringSELECT id, tagFROM products, JSONB_ARRAY_ELEMENTS_TEXT(tags) AS tagWHERE tag = 'electronics';JSONB_EACH
Section titled “JSONB_EACH”JSONB_EACH JSONB_EACH(from_json JSONB)→ SETOF (key TEXT, value JSONB) Expands a JSON object into a set of (key, value) rows, one row per top-level key. Use JSONB_EACH_TEXT to get both key and value as TEXT.
SELECT key, value FROM JSONB_EACH('{"a":1,"b":2,"c":3}'::jsonb);-- key | value-- a | 1-- b | 2-- c | 3
-- Pivot metadata keys into rowsSELECT id, key, value::textFROM users, JSONB_EACH_TEXT(metadata)WHERE key LIKE 'pref_%';JSON Operators
Section titled “JSON Operators”| Operator | Description | Example |
|---|---|---|
-> | Get JSON element by key/index | data->'name' |
->> | Get JSON element as text | data->>'name' |
#> | Get element by path | data#>'{addr,city}' |
#>> | Get element by path as text | data#>>'{addr,city}' |
#- | Delete key/path | data #- '{addr}' |
@> | Contains | data @> '{"a":1}' |
<@ | Contained by | '{"a":1}' <@ data |
? | Key exists | data ? 'email' |
?| | Any key exists | data ?| array['a','b'] |
?& | All keys exist | data ?& array['a','b'] |
Array Functions
Section titled “Array Functions”ARRAY_LENGTH / ARRAY_UPPER / ARRAY_LOWER / CARDINALITY
Section titled “ARRAY_LENGTH / ARRAY_UPPER / ARRAY_LOWER / CARDINALITY”ARRAY_LENGTH(array, dimension INT) → INT — Length of the array along the given dimension (1-based).
ARRAY_UPPER(array, dimension INT) → INT — Upper bound of array dimension.
ARRAY_LOWER(array, dimension INT) → INT — Lower bound of array dimension (usually 1).
CARDINALITY(array) → INT — Total number of elements across all dimensions.
SELECT ARRAY_LENGTH(ARRAY[1,2,3], 1); -- 3SELECT ARRAY_UPPER(ARRAY[1,2,3], 1); -- 3SELECT ARRAY_LOWER(ARRAY[1,2,3], 1); -- 1SELECT CARDINALITY(ARRAY[[1,2],[3,4]]); -- 4ARRAY_POSITION
Section titled “ARRAY_POSITION”ARRAY_POSITION(array, element [, subscript INT]) → INT — Returns the position of the first occurrence of element in array (1-based; NULL if not found).
SELECT ARRAY_POSITION(ARRAY['a','b','c','b'], 'b'); -- 2SELECT ARRAY_POSITION(ARRAY['a','b','c','b'], 'b', 3); -- 4 (start from position 3)ARRAY_CAT / ARRAY_APPEND / ARRAY_PREPEND / ARRAY_REMOVE
Section titled “ARRAY_CAT / ARRAY_APPEND / ARRAY_PREPEND / ARRAY_REMOVE”ARRAY_CAT(array1, array2) → ARRAY — Concatenates two arrays. Equivalent to || operator.
ARRAY_APPEND(array, element) → ARRAY — Appends an element to the end.
ARRAY_PREPEND(element, array) → ARRAY — Prepends an element to the beginning.
ARRAY_REMOVE(array, element) → ARRAY — Removes all occurrences of element.
SELECT ARRAY_CAT(ARRAY[1,2], ARRAY[3,4]); -- {1,2,3,4}SELECT ARRAY_APPEND(ARRAY[1,2,3], 4); -- {1,2,3,4}SELECT ARRAY_PREPEND(0, ARRAY[1,2,3]); -- {0,1,2,3}SELECT ARRAY_REMOVE(ARRAY[1,2,3,2], 2); -- {1,3}ARRAY_TO_STRING / STRING_TO_ARRAY
Section titled “ARRAY_TO_STRING / STRING_TO_ARRAY”ARRAY_TO_STRING(array, delimiter TEXT [, null_string TEXT]) → TEXT — Converts array to a delimited string.
STRING_TO_ARRAY(string TEXT, delimiter TEXT [, null_string TEXT]) → TEXT[] — Splits a string into a text array.
SELECT ARRAY_TO_STRING(ARRAY[1,2,3], ','); -- '1,2,3'SELECT ARRAY_TO_STRING(ARRAY['a',NULL,'c'], ',', 'X'); -- 'a,X,c'SELECT STRING_TO_ARRAY('a,b,c', ','); -- {a,b,c}UNNEST
Section titled “UNNEST”UNNEST UNNEST(array ANYARRAY [, array2, ...])→ SETOF element Expands an array into a set of rows. Multiple arrays are expanded in parallel. Use WITH ORDINALITY to get element positions.
SELECT UNNEST(ARRAY['a','b','c']);-- a / b / c
SELECT val, pos FROM UNNEST(ARRAY['x','y','z']) WITH ORDINALITY AS t(val, pos);-- x|1, y|2, z|3ARRAY_LENGTH
Section titled “ARRAY_LENGTH”ARRAY_LENGTH ARRAY_LENGTH(array ANYARRAY, dimension INT)→ INT Returns the length of the requested array dimension. For 1-D arrays, dimension is 1. Returns NULL for an empty array. CARDINALITY() is a simpler alternative that returns the total element count of a 1-D array.
SELECT ARRAY_LENGTH(ARRAY[1, 2, 3, 4, 5], 1); -- 5SELECT ARRAY_LENGTH(ARRAY[['a','b'],['c','d']], 2); -- 2 (second dimension)SELECT CARDINALITY(ARRAY[1,2,3]); -- 3UNNEST
Section titled “UNNEST”UNNEST UNNEST(array ANYARRAY [, array2, ...])→ SETOF element Expands an array into a set of rows, one row per element. When multiple arrays are provided, they are expanded in parallel (zip), stopping at the shortest. Use WITH ORDINALITY to get element positions.
SELECT UNNEST(ARRAY['a', 'b', 'c']);-- a-- b-- c
-- With ordinality to get element positionSELECT val, posFROM UNNEST(ARRAY['x','y','z']) WITH ORDINALITY AS t(val, pos);-- x | 1-- y | 2-- z | 3
-- Join array column elements as rowsSELECT id, tagFROM articles, UNNEST(tags) AS tagWHERE 'postgres' = ANY(tags);Regular Expression Functions
Section titled “Regular Expression Functions”REGEXP_REPLACE
Section titled “REGEXP_REPLACE”REGEXP_REPLACE REGEXP_REPLACE(string TEXT, pattern TEXT, replacement TEXT [, flags TEXT])→ TEXT Replaces POSIX regex matches. Flags: g = replace all, i = case-insensitive. Use \\1, \\2 for back-references.
SELECT REGEXP_REPLACE('foo bar baz', '\s+', '-', 'g'); -- 'foo-bar-baz'SELECT REGEXP_REPLACE(' trim ', '^\s+|\s+$', '', 'g'); -- 'trim'REGEXP_SPLIT_TO_ARRAY
Section titled “REGEXP_SPLIT_TO_ARRAY”REGEXP_SPLIT_TO_ARRAY(string TEXT, pattern TEXT [, flags TEXT]) → TEXT[] — Splits string using a regular expression delimiter, returning a text array.
SELECT REGEXP_SPLIT_TO_ARRAY('one two three', '\s+');-- {one,two,three}REGEXP_REPLACE
Section titled “REGEXP_REPLACE”REGEXP_REPLACE REGEXP_REPLACE(string TEXT, pattern TEXT, replacement TEXT [, flags TEXT])→ TEXT Replaces substring(s) matching a POSIX regular expression. By default replaces only the first match; use the 'g' flag to replace all occurrences. Use \\1, \\2 in replacement for back-references.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
string | TEXT | Yes | — | Input string |
pattern | TEXT | Yes | — | POSIX regular expression |
replacement | TEXT | Yes | — | Replacement string; use \1, \2 for capture group back-references |
flags | TEXT | No | '' | g = replace all matches, i = case-insensitive |
SELECT REGEXP_REPLACE('Hello World', 'World', 'DB9'); -- 'Hello DB9'SELECT REGEXP_REPLACE('abc123def', '[0-9]+', 'NUM'); -- 'abcNUMdef'SELECT REGEXP_REPLACE(' spaces ', '^\s+|\s+$', '', 'g'); -- 'spaces'SELECT REGEXP_REPLACE('foo bar baz', '\s+', '-', 'g'); -- 'foo-bar-baz'Regular Expression Operators
Section titled “Regular Expression Operators”| Operator | Description |
|---|---|
~ | Matches regex (case-sensitive) |
~* | Matches regex (case-insensitive) |
!~ | Does not match (case-sensitive) |
!~* | Does not match (case-insensitive) |
Full-Text Search
Section titled “Full-Text Search”TO_TSVECTOR
Section titled “TO_TSVECTOR”TO_TSVECTOR([config REGCONFIG,] document TEXT) → TSVECTOR — Converts text to a tsvector of lexemes for full-text search. The optional config sets the text search configuration (e.g. 'english').
SELECT TO_TSVECTOR('english', 'the quick brown fox');-- 'brown':3 'fox':4 'quick':2
-- Indexed column (GIN index recommended)CREATE INDEX ON articles USING GIN (TO_TSVECTOR('english', body));TO_TSQUERY / PLAINTO_TSQUERY / PHRASETO_TSQUERY / WEBSEARCH_TO_TSQUERY
Section titled “TO_TSQUERY / PLAINTO_TSQUERY / PHRASETO_TSQUERY / WEBSEARCH_TO_TSQUERY”TO_TSQUERY([config,] querytext TEXT) → TSQUERY — Parses a query string with explicit operators (&, |, !, <->).
PLAINTO_TSQUERY([config,] querytext TEXT) → TSQUERY — Converts plain text to a tsquery treating all words as AND-joined terms.
PHRASETO_TSQUERY([config,] querytext TEXT) → TSQUERY — Creates a phrase query requiring words to appear adjacent.
WEBSEARCH_TO_TSQUERY([config,] querytext TEXT) → TSQUERY — Converts web-search style query (quoted phrases, - exclusions) to a tsquery.
SELECT TO_TSQUERY('english', 'quick & fox');SELECT PLAINTO_TSQUERY('english', 'quick brown fox');SELECT PHRASETO_TSQUERY('english', 'quick brown'); -- adjacent wordsSELECT WEBSEARCH_TO_TSQUERY('english', '"quick brown" -slow');SETWEIGHT
Section titled “SETWEIGHT”SETWEIGHT SETWEIGHT(vector TSVECTOR, weight "char")→ TSVECTOR Assigns weight A/B/C/D to all lexemes in a tsvector. A is highest, D is default. Used to boost specific fields in TS_RANK scoring.
SELECT SETWEIGHT(TO_TSVECTOR('english', title), 'A') || SETWEIGHT(TO_TSVECTOR('english', body), 'C') AS docFROM articles;TS_RANK / TS_RANK_CD
Section titled “TS_RANK / TS_RANK_CD”TS_RANK TS_RANK(vector TSVECTOR, query TSQUERY [, normalization INT])→ FLOAT4 Calculates a relevance score. Higher = more relevant. normalization bitmask controls length normalization: 0=none, 1=1/log(ndoc), 2=1/ndoc.
TS_RANK_CD(vector, query [, normalization]) — Like TS_RANK but uses the “cover density” ranking algorithm, which also factors in how close matches are to each other.
SELECT title, TS_RANK(TO_TSVECTOR('english', body), query) AS rankFROM articles, PLAINTO_TSQUERY('english', 'database') AS queryWHERE TO_TSVECTOR('english', body) @@ queryORDER BY rank DESC LIMIT 10;TS_HEADLINE
Section titled “TS_HEADLINE”TS_HEADLINE([config REGCONFIG,] document TEXT, query TSQUERY [, options TEXT]) → TEXT — Highlights matching terms in a document fragment. Options include StartSel, StopSel, MaxWords, MinWords, ShortWord, HighlightAll, MaxFragments, FragmentDelimiter.
SELECT TS_HEADLINE( 'english', body, PLAINTO_TSQUERY('english', 'database performance'), 'StartSel=<b>, StopSel=</b>, MaxFragments=2') AS headlineFROM articlesWHERE TO_TSVECTOR('english', body) @@ PLAINTO_TSQUERY('english', 'database performance');SETWEIGHT
Section titled “SETWEIGHT”SETWEIGHT SETWEIGHT(vector TSVECTOR, weight "char")→ TSVECTOR Assigns a weight label to all lexemes in a tsvector. Weights are A (highest), B, C, D (lowest/default). Used to boost certain document fields (e.g. title vs body) when scoring with TS_RANK.
-- Weight title higher than bodySELECT SETWEIGHT(TO_TSVECTOR('english', title), 'A') || SETWEIGHT(TO_TSVECTOR('english', body), 'C') AS documentFROM articles;
-- Indexed column with weighted fieldsCREATE INDEX ON articles USING GIN ( SETWEIGHT(TO_TSVECTOR('english', title), 'A') || SETWEIGHT(TO_TSVECTOR('english', body), 'C'));TS_RANK
Section titled “TS_RANK”TS_RANK TS_RANK(vector TSVECTOR, query TSQUERY [, normalization INT])→ FLOAT4 Calculates a relevance score for a tsvector against a tsquery. Higher scores indicate better matches. The normalization bitmask controls whether document length affects the score.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
vector | TSVECTOR | Yes | — | Document tsvector (often a stored/indexed column) |
query | TSQUERY | Yes | — | Search query |
normalization | INT | No | 0 | Bitmask: 0=none, 1=1/log(ndoc), 2=1/ndoc, 4=mean harmonic distance, 8=unique words, 16=1/log(unique words), 32=rank/(rank+1) |
SELECT title, TS_RANK( TO_TSVECTOR('english', body), PLAINTO_TSQUERY('english', 'database performance') ) AS rankFROM articlesWHERE TO_TSVECTOR('english', body) @@ PLAINTO_TSQUERY('english', 'database performance')ORDER BY rank DESCLIMIT 10;UUID Functions
Section titled “UUID Functions”GEN_RANDOM_UUID() → UUID — Generates a random UUID v4. This is the standard way to generate UUIDs in PostgreSQL 13+.
UUID_GENERATE_V4() → UUID — Generates a random UUID v4 (requires uuid-ossp extension). Prefer GEN_RANDOM_UUID().
UUIDV7() → UUID — Generates a UUID v7 (time-ordered, monotonically increasing). Useful for primary keys that sort by creation time.
SELECT GEN_RANDOM_UUID(); -- e.g. 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11'SELECT UUIDV7(); -- time-ordered UUID v7
-- Common primary key patternCREATE TABLE events ( id UUID PRIMARY KEY DEFAULT UUIDV7(), name TEXT NOT NULL);Encoding & Hashing
Section titled “Encoding & Hashing”ENCODE / DECODE
Section titled “ENCODE / DECODE”ENCODE(data BYTEA, format TEXT) → TEXT — Encodes binary as text. Formats: base64, hex, escape.
DECODE(string TEXT, format TEXT) → BYTEA — Decodes text back to binary.
SELECT ENCODE('Hello'::bytea, 'base64'); -- 'SGVsbG8='SELECT ENCODE('Hello'::bytea, 'hex'); -- '48656c6c6f'SELECT DECODE('SGVsbG8=', 'base64'); -- '\x48656c6c6f'MD5(string TEXT) → TEXT — Returns a 32-character lowercase MD5 hex digest. Not suitable for security use.
SELECT MD5('hello'); -- '5d41402abc4b2a76b9719d911017c592'ENCODE / DECODE
Section titled “ENCODE / DECODE”ENCODE ENCODE(data BYTEA, format TEXT)→ TEXT Encodes binary data as text. Supported formats: base64, hex, escape.
DECODE DECODE(string TEXT, format TEXT)→ BYTEA Decodes text-encoded binary data back to BYTEA. Supported formats: base64, hex, escape.
SELECT ENCODE('Hello DB9'::bytea, 'base64'); -- 'SGVsbG8gREI5'SELECT ENCODE('Hello DB9'::bytea, 'hex'); -- '48656c6c6f2044423'...
SELECT DECODE('SGVsbG8gREI5', 'base64'); -- '\x48656c6c6f204442...'MD5 MD5(string TEXT)→ TEXT Returns the MD5 hash of a string as a lowercase 32-character hex string. Not recommended for security-sensitive hashing.
SELECT MD5('hello'); -- '5d41402abc4b2a76b9719d911017c592'SELECT MD5(RANDOM()::text); -- random 32-char hex stringVector Functions (pgvector-compatible)
Section titled “Vector Functions (pgvector-compatible)”L2_DISTANCE(a VECTOR, b VECTOR) → FLOAT8 — Euclidean (L2) distance between two vectors. Equivalent to a <-> b.
INNER_PRODUCT(a VECTOR, b VECTOR) → FLOAT8 — Dot product. Negative inner product via a <#> b.
COSINE_DISTANCE(a VECTOR, b VECTOR) → FLOAT8 — Cosine distance (1 - cosine similarity). Equivalent to a <=> b.
VECTOR_DIMS(v VECTOR) → INT — Returns the number of dimensions.
VECTOR_NORM(v VECTOR) → FLOAT8 — Returns the Euclidean norm (magnitude).
-- Similarity searchSELECT id, embedding <-> query_vec AS distanceFROM itemsORDER BY embedding <-> query_vecLIMIT 10;
SELECT VECTOR_DIMS('[1,2,3]'::vector); -- 3SELECT VECTOR_NORM('[3,4]'::vector); -- 5Embedding Functions
Section titled “Embedding Functions”EMBEDDING(text TEXT [, model TEXT, dimensions INT]) → VECTOR — Generates a vector embedding inline in SQL.
EMBED_TEXT(model TEXT, text TEXT [, json_options JSONB]) → VECTOR — Explicit model-specified embedding function.
-- Requires: CREATE EXTENSION embeddingSELECT EMBEDDING('hello world'); -- uses default model
-- Semantic searchSELECT id, titleFROM docsORDER BY EMBEDDING(title) <=> EMBEDDING('database connection')LIMIT 5;See Vector Search for end-to-end examples.
Document Chunking
Section titled “Document Chunking”CHUNK_TEXT(content TEXT [, max_chars INT, overlap_chars INT, title TEXT]) — Table-valued function that splits text into overlapping chunks for RAG pipelines. Markdown-aware at paragraph, heading, and list boundaries.
SELECT chunk_index, chunk_text, char_countFROM CHUNK_TEXT('Long document...', 500, 50, 'My Doc');See CHUNK_TEXT for full reference.
HTTP Functions (Scalar)
Section titled “HTTP Functions (Scalar)”HTTP_GET(url TEXT) → JSONB — Sends a GET request.
HTTP_POST(url TEXT, body TEXT, content_type TEXT) → JSONB — Sends a POST request.
HTTP_PUT(url TEXT, body TEXT, content_type TEXT) → JSONB — Sends a PUT request.
HTTP_DELETE(url TEXT) → JSONB — Sends a DELETE request.
HTTP_HEAD(url TEXT) → JSONB — Sends a HEAD request.
HTTP_PATCH(url TEXT, body TEXT, content_type TEXT) → JSONB — Sends a PATCH request.
HTTP(method TEXT, url TEXT, body TEXT, options JSONB) → JSONB — Generic HTTP function.
All return JSONB with keys: status (INT), content (TEXT), content_type (TEXT), headers (JSONB).
SELECT (HTTP_GET('https://api.example.com/data'))->>'content';
SELECT (HTTP_POST( 'https://api.example.com/items', '{"name":"test"}', 'application/json' ))->>'status'; -- e.g. '201'See http extension for details.
Storage Functions
Section titled “Storage Functions”DB9_REFRESH_STORAGE_STATS() → VOID — Triggers an asynchronous storage scan. Results appear in _DB9_SYS_STORAGE_STATS and _DB9_SYS_TABLE_STORAGE_STATS. See Storage Accounting.
FS9_STORAGE_STATS() → TABLE(total_files BIGINT, total_directories BIGINT, total_logical_bytes BIGINT) — Returns filesystem storage statistics. Requires the fs9 extension. See fs9 extension.
Sequence Functions
Section titled “Sequence Functions”NEXTVAL(regclass) → BIGINT — Advances a sequence and returns the new value.
CURRVAL(regclass) → BIGINT — Returns the last value from NEXTVAL in the current session.
SETVAL(regclass, value BIGINT [, called BOOLEAN]) → BIGINT — Sets the current value of a sequence.
LASTVAL() → BIGINT — Returns the last value returned by NEXTVAL in the current session, for any sequence.
PG_GET_SERIAL_SEQUENCE(table_name TEXT, column_name TEXT) → TEXT — Returns the name of the sequence associated with a serial column.
SELECT NEXTVAL('my_seq');SELECT CURRVAL('my_seq');SELECT SETVAL('my_seq', 100); -- next NEXTVAL returns 101SELECT SETVAL('my_seq', 100, false); -- next NEXTVAL returns 100
SELECT PG_GET_SERIAL_SEQUENCE('users', 'id'); -- e.g. 'public.users_id_seq'Conditional Expressions
Section titled “Conditional Expressions”COALESCE
Section titled “COALESCE”COALESCE COALESCE(value1 ANY, value2 ANY [, ...])→ same type Returns the first non-NULL argument, evaluated left-to-right. All arguments must be of compatible types.
SELECT COALESCE(NULL, NULL, 'fallback'); -- 'fallback'SELECT COALESCE(nickname, first_name, 'Anonymous') FROM users;NULLIF
Section titled “NULLIF”NULLIF(value1 ANY, value2 ANY) → same type — Returns NULL if value1 = value2, otherwise returns value1. The inverse of COALESCE.
SELECT NULLIF(0, 0); -- NULL (avoids division by zero)SELECT 100 / NULLIF(divisor, 0) FROM t; -- safe divisionGREATEST / LEAST
Section titled “GREATEST / LEAST”GREATEST(val1, val2, ...) → same type — Returns the largest non-NULL value among arguments.
LEAST(val1, val2, ...) → same type — Returns the smallest non-NULL value among arguments.
SELECT GREATEST(1, 5, 3, 2); -- 5SELECT LEAST('apple', 'banana', 'cherry'); -- 'apple'CASE WHEN
Section titled “CASE WHEN”-- Searched CASESELECT CASE WHEN score >= 90 THEN 'A' WHEN score >= 80 THEN 'B' WHEN score >= 70 THEN 'C' ELSE 'F' END AS gradeFROM students;
-- Simple CASESELECT CASE status WHEN 'active' THEN 'Active' WHEN 'inactive' THEN 'Inactive' ELSE 'Unknown' END AS labelFROM users;COALESCE
Section titled “COALESCE”COALESCE COALESCE(value1 ANY, value2 ANY [, ...])→ same type Returns the first non-NULL argument, evaluating left-to-right and stopping at the first non-NULL value. All arguments must be of compatible types. The classic null-safe fallback function.
SELECT COALESCE(NULL, NULL, 'fallback'); -- 'fallback'SELECT COALESCE(nickname, first_name, 'Anonymous') FROM users; -- first non-null name
-- Provide 0 instead of NULL for aggregatesSELECT user_id, COALESCE(SUM(amount), 0) AS totalFROM ordersGROUP BY user_id;System / Compatibility Functions
Section titled “System / Compatibility Functions”GENERATE_SERIES
Section titled “GENERATE_SERIES”GENERATE_SERIES GENERATE_SERIES(start, stop [, step])→ SETOF value Generates values from start to stop (inclusive). Works with INT, NUMERIC, TIMESTAMP, TIMESTAMPTZ. Default step is 1 or '1 day'.
SELECT * FROM GENERATE_SERIES(1, 5);SELECT * FROM GENERATE_SERIES('2024-01-01'::date, '2024-01-07'::date, '1 day');
-- Fill time-series gapsSELECT d.day, COALESCE(COUNT(o.id), 0) AS ordersFROM GENERATE_SERIES('2024-01-01'::date, '2024-01-31'::date, '1 day') d(day)LEFT JOIN orders o ON o.created_at::date = d.dayGROUP BY d.day ORDER BY d.day;PG_TYPEOF
Section titled “PG_TYPEOF”PG_TYPEOF(any) → REGTYPE — Returns the data type of its argument.
SELECT PG_TYPEOF(42); -- 'integer'SELECT PG_TYPEOF('hello'); -- 'unknown'SELECT PG_TYPEOF(NOW()); -- 'timestamp with time zone'SIZE FUNCTIONS
Section titled “SIZE FUNCTIONS”PG_COLUMN_SIZE(any) → INT — Number of bytes used to store a particular value.
SELECT PG_COLUMN_SIZE(ROW(1, 'hello', NOW()));PRIVILEGE FUNCTIONS
Section titled “PRIVILEGE FUNCTIONS”HAS_TABLE_PRIVILEGE(user TEXT, table TEXT, privilege TEXT) → BOOLEAN — Tests if user has privilege on table.
HAS_SCHEMA_PRIVILEGE(user TEXT, schema TEXT, privilege TEXT) → BOOLEAN — Tests schema privilege.
HAS_DATABASE_PRIVILEGE(user TEXT, database TEXT, privilege TEXT) → BOOLEAN — Tests database privilege.
SELECT HAS_TABLE_PRIVILEGE('alice', 'public.users', 'SELECT');SELECT HAS_SCHEMA_PRIVILEGE(CURRENT_USER, 'public', 'USAGE');DESCRIPTION FUNCTIONS
Section titled “DESCRIPTION FUNCTIONS”OBJ_DESCRIPTION(oid OID, catalog_name TEXT) → TEXT — Returns the comment (description) for a database object.
COL_DESCRIPTION(table_oid OID, column_number INT) → TEXT — Returns the comment for a table column.
SELECT OBJ_DESCRIPTION('public.users'::regclass, 'pg_class');SELECT COL_DESCRIPTION('public.users'::regclass, 1);SYSTEM INFO
Section titled “SYSTEM INFO”VERSION() → TEXT — Returns a string describing the server version.
CURRENT_USER → TEXT — Name of the current effective user.
CURRENT_DATABASE() → NAME — Name of the current database.
CURRENT_SCHEMA() → NAME — Current schema search path default.
PG_BACKEND_PID() → INT — Process ID of the server process for the current session.
FORMAT_TYPE(type_oid OID, typemod INT) → TEXT — Returns the SQL name of a data type.
PG_ENCODING_TO_CHAR(encoding INT) → TEXT — Converts an encoding number to its name.
SELECT VERSION();SELECT CURRENT_USER, CURRENT_DATABASE(), CURRENT_SCHEMA();SELECT PG_BACKEND_PID();GENERATE_SERIES
Section titled “GENERATE_SERIES”GENERATE_SERIES GENERATE_SERIES(start, stop [, step])→ SETOF value Generates a series of values from start to stop (inclusive), incrementing by step. Works with integers, numerics, timestamps, and timestamptz. Default step is 1 for numerics or 1 day for timestamps.
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
start | INT | NUMERIC | TIMESTAMP | TIMESTAMPTZ | Yes | — | Series start value (inclusive) |
stop | same as start | Yes | — | Series end value (inclusive) |
step | INT | NUMERIC | INTERVAL | No | 1 | Increment between values |
SELECT * FROM GENERATE_SERIES(1, 5); -- 1, 2, 3, 4, 5SELECT * FROM GENERATE_SERIES(0, 1, 0.25); -- 0, 0.25, 0.50, 0.75, 1.00
-- Generate a date rangeSELECT * FROM GENERATE_SERIES( '2024-01-01'::date, '2024-01-07'::date, '1 day'::interval) AS day;
-- Fill time-series gaps with LEFT JOINSELECT d.day, COALESCE(COUNT(o.id), 0) AS ordersFROM GENERATE_SERIES('2024-01-01'::date, '2024-01-31'::date, '1 day') AS d(day)LEFT JOIN orders o ON o.created_at::date = d.dayGROUP BY d.dayORDER BY d.day;Background SQL
Section titled “Background SQL”PG_BACKGROUND_LAUNCH(sql TEXT) → INT — Launches a SQL statement asynchronously in a background session. Returns a handle (integer).
PG_BACKGROUND_RESULT(handle INT) → SETOF RECORD — Waits for and retrieves the result of a background query by handle.
-- Launch a long-running query in the backgroundSELECT PG_BACKGROUND_LAUNCH('VACUUM ANALYZE large_table') AS handle;-- Returns: 12345
-- Collect the resultSELECT * FROM PG_BACKGROUND_RESULT(12345) AS r(status TEXT);