KDB knowledge

Text functions

Change case, cut, trim, pad, search and join text. A letter of any language (Nepali, Chinese, ...) counts as one character.

These functions work on text (STRING). KDB keeps text as UTF-8. UTF-8 is the usual way to store the letters of every language. An English letter takes 1 byte; a Nepali letter like न takes 3 bytes.

Example: Clean labels for the company list (sample data: sample)

SELECT symbol,
       lower(symbol) AS url_part,
       split_part(name, ' ', 1) AS first_word,
       length(name) AS letters,
       symbol || ' - ' || left(name, 20) AS label
FROM securities
ORDER BY symbol;

Result:

symbol (SYMBOL)url_part (STRING)first_word (STRING)letters (LONG)label (STRING)
ACMEacmeAcme23ACME - Acme Investment Comp
CITYcityCity17CITY - City Bank Limited
COASTcoastCoastal20COAST - Coastal Bank Limited
TELCOtelcoNorthwind25TELCO - Northwind Telecom Li
VOLTvoltVolt29VOLT - Volt River Hydropowe

(5 rows)

lower

Syntax:

lower(text)

The text with every capital letter made small: lower('CITY') is city, lower('ÄÖ') is äö, lower('ΣΑΣ') is σασ. Letters without capitals (Nepali) stay as they are.

ArgumentTypeMeaning
textSTRING (a number is turned into text)the text to change

Example

SELECT lower('CITY Bank') AS a, lower('नेपाल') AS nepali, lower('ÄBC') AS german, lower('ПРИВЕТ') AS russian, lower(NULL) AS b;

Result:

a (STRING)nepali (STRING)german (STRING)russian (STRING)b (STRING)
city bankनेपालäbcприветNULL

(1 row)

Example: Log in with the user name in any case

Setup:

CREATE TABLE app_users (id INT PRIMARY KEY AUTO, username STRING NOT NULL, email STRING);
INSERT INTO app_users (username, email) VALUES ('Ram_Sharma', 'ram@example.com'), ('sita', 'sita@example.com');
SELECT id, username FROM app_users WHERE lower(username) = lower('RAM_sharma');

Result:

id (INT)username (STRING)
1Ram_Sharma

(1 row)

upper

Syntax:

upper(text)

The text with every small letter made capital: upper('city') is CITY, upper('ěšč') is ĚŠČ. Letters without capitals (Nepali) stay as they are.

ArgumentTypeMeaning
textSTRING (a number is turned into text)the text to change

Example

SELECT upper('city नेपाल') AS a, upper('Coast') AS b, upper('crème brûlée') AS french, upper(NULL) AS c;

Result:

a (STRING)b (STRING)french (STRING)c (STRING)
CITY नेपालCOASTCRÈME BRÛLÉENULL

(1 row)

Example: Clean stock symbols typed by users

Setup:

CREATE TABLE watchlist (id INT PRIMARY KEY AUTO, typed STRING);
INSERT INTO watchlist (typed) VALUES ('  city '), ('Coast'), ('volt  ');
SELECT id, '[' || typed || ']' AS typed, upper(trim(typed)) AS symbol FROM watchlist ORDER BY id;

Result:

id (INT)typed (STRING)symbol (STRING)
1[ city ]CITY
2[Coast]COAST
3[volt ]VOLT

(3 rows)

length, char_length, character_length

Syntax:

length(text)
char_length(text)
character_length(text)

The number of characters in the text. A Nepali letter is one character. The three names are the same function.

ArgumentTypeMeaning
textSTRING, BYTES, or a value turned into textthe value to measure

Example

SELECT length('CITY') AS a, length('नेपाल') AS nepali, length('के') AS ke, char_length('') AS empty, character_length('City Bank') AS b, length(12.50) AS number, length(NULL) AS c;

Result:

a (LONG)nepali (LONG)ke (LONG)empty (LONG)b (LONG)number (LONG)c (STRING)
452094NULL

(1 row)

Example: Refuse a forum post that is too short or too long

SELECT body, length(body) AS letters, length(body) BETWEEN 10 AND 500 AS ok
FROM (SELECT 'Good results!' AS body
      UNION ALL SELECT 'नाफा राम्रो छ'
      UNION ALL SELECT 'ok') AS posts;

Result:

body (STRING)letters (LONG)ok (BOOL)
Good results!13true
नाफा राम्रो छ13true
ok2false

(3 rows)

Example: Company names in English and Nepali

Setup:

CREATE TABLE companies (symbol STRING PRIMARY KEY, name STRING, name_ne STRING);
INSERT INTO companies VALUES ('CITY', 'City Bank Limited', 'सिटी बैंक लिमिटेड'), ('VOLT', 'Volt River Hydropower Limited', 'भोल्ट रिभर जलविद्युत लिमिटेड');
SELECT symbol, length(name) AS name_letters, name_ne, length(name_ne) AS ne_letters FROM companies ORDER BY symbol;

Result:

symbol (STRING)name_letters (LONG)name_ne (STRING)ne_letters (LONG)
CITY17सिटी बैंक लिमिटेड17
VOLT29भोल्ट रिभर जलविद्युत लिमिटेड28

(2 rows)

octet_length

Syntax:

octet_length(text)

The number of bytes the text takes in UTF-8. An English letter is 1 byte; a Nepali letter is 3 bytes.

ArgumentTypeMeaning
textSTRING, BYTES, or a value turned into textthe value to measure

Example

SELECT length('नेपाल') AS letters, octet_length('नेपाल') AS bytes, octet_length('CITY') AS english_bytes, octet_length('') AS empty;

Result:

letters (LONG)bytes (LONG)english_bytes (LONG)empty (LONG)
51540

(1 row)

substr, substring

Syntax:

substr(text, start)
substr(text, start, count)
substring(text, start [, count])

A part of the text: count characters from character number start. The first character is number 1. Without count, you get everything to the end. substring is the same function.

ArgumentTypeMeaning
textSTRING (or BYTES)the text to cut
startwhole numberthe first character to keep; 1 = first. 0 or less starts before the text, so fewer characters are left
countwhole numberhow many characters; must not be negative

Example

SELECT substr('CITY', 3) AS a, substring('CITY', 2, 3) AS b, substr('नेपाल', 2, 2) AS nepali, substr('CITY', 0, 3) AS from_zero, substr('CITY', 10) AS after_end;

Result:

a (STRING)b (STRING)nepali (STRING)from_zero (STRING)after_end (STRING)
TYITYेपCI

(1 row)

Example: Nepali fiscal year 2082/83: first and last year

SELECT substr('2082/83', 1, 4) AS first_year, substr('2082/83', 6) AS second_year;

Result:

first_year (STRING)second_year (STRING)
208283

(1 row)

Example: A negative count is an error (shows an error)

SELECT substr('CITY', 2, -1);

Result:

Error: line 1, column 8: substr: the length must not be negative, got -1

Example: The PostgreSQL FROM ... FOR form

SELECT substring('CITY' FROM 2 FOR 3) AS from_for, substring('CITY' FROM 2) AS to_the_end;

Result:

from_for (STRING)to_the_end (STRING)
ITYITY

(1 row)

left

Syntax:

left(text, n)

The first n characters of the text. With a negative n, everything except the last -n characters.

ArgumentTypeMeaning
textSTRINGthe text
nwhole numberhow many characters to keep from the start; negative = how many to drop from the end

Example

SELECT left('CITY', 3) AS a, left('CITY', -2) AS drop_last_2, left('नेपाल बैंक', 5) AS nepali, left('CITY', 99) AS whole;

Result:

a (STRING)drop_last_2 (STRING)nepali (STRING)whole (STRING)
CITCIनेपालCITY

(1 row)

Example: Short preview of long company names (sample data: sample)

SELECT symbol,
       CASE WHEN length(name) > 25 THEN left(name, 25) || '...' ELSE name END AS preview
FROM securities
ORDER BY symbol;

Result:

symbol (SYMBOL)preview (STRING)
ACMEAcme Investment Company
CITYCity Bank Limited
COASTCoastal Bank Limited
TELCONorthwind Telecom Limited
VOLTVolt River Hydropower Lim...

(5 rows)

Syntax:

right(text, n)

The last n characters of the text. With a negative n, everything except the first -n characters.

ArgumentTypeMeaning
textSTRINGthe text
nwhole numberhow many characters to keep from the end; negative = how many to drop from the start

Example

SELECT right('CITY', 3) AS a, right('CITY', -2) AS drop_first_2, right('नेपाल', 2) AS nepali;

Result:

a (STRING)drop_first_2 (STRING)nepali (STRING)
ITYTYाल

(1 row)

Example: Show only the last 4 digits of a phone number

SELECT '******' || right('9841234567', 4) AS phone_shown;

Result:

phone_shown (STRING)
******4567

(1 row)

trim, btrim

Syntax:

trim(text)
trim(text, characters)
btrim(text [, characters])

Removes spaces from both ends of the text. With characters, it removes any of those characters from both ends instead. btrim is the same function.

ArgumentTypeMeaning
textSTRINGthe text to clean
charactersSTRINGthe characters to remove, in any order; default: space, tab, carriage return and line break

Example

SELECT '[' || trim('  CITY  ') || ']' AS a, trim('xxCOASTxx', 'x') AS b, btrim('--a-b--', '-') AS c, trim('xyCITYyx', 'xy') AS d;

Result:

a (STRING)b (STRING)c (STRING)d (STRING)
[CITY]COASTa-bCITY

(1 row)

Example: Clean a user name before saving it

Setup:

CREATE TABLE app_users (id INT PRIMARY KEY AUTO, username STRING NOT NULL);
INSERT INTO app_users (username) VALUES (lower(trim('   Hari_KC  ')));
SELECT id, '[' || username || ']' AS saved FROM app_users;

Result:

INSERT INTO app_users (username) VALUES (lower(trim(' Hari_KC ')))

1 row(s) inserted

SELECT id, '[' || username || ']' AS saved FROM app_users

id (INT)saved (STRING)
1[hari_kc]

(1 row)

Example: The standard BOTH / LEADING / TRAILING forms

SELECT trim(BOTH 'x' FROM 'xxCOASTxx') AS both_ends,
       trim(LEADING 'x' FROM 'xxCOASTxx') AS front_only,
       trim(TRAILING 'x' FROM 'xxCOASTxx') AS end_only;

Result:

both_ends (STRING)front_only (STRING)end_only (STRING)
COASTCOASTxxxxCOAST

(1 row)

ltrim

Syntax:

ltrim(text [, characters])

Like trim, but only at the start (left side) of the text.

ArgumentTypeMeaning
textSTRINGthe text to clean
charactersSTRINGthe characters to remove; default: space, tab, carriage return and line break

Example

SELECT '[' || ltrim('   CITY  ') || ']' AS a, ltrim('00042', '0') AS no_zeros;

Result:

a (STRING)no_zeros (STRING)
[CITY ]42

(1 row)

rtrim

Syntax:

rtrim(text [, characters])

Like trim, but only at the end (right side) of the text.

ArgumentTypeMeaning
textSTRINGthe text to clean
charactersSTRINGthe characters to remove; default: space, tab, carriage return and line break

Example

SELECT '[' || rtrim('  CITY   ') || ']' AS a, rtrim('नेपाल।।', '।') AS nepali_full_stop, rtrim('512.500', '0') AS price;

Result:

a (STRING)nepali_full_stop (STRING)price (STRING)
[ CITY]नेपाल512.5

(1 row)

replace

Syntax:

replace(text, from, to)

Replaces every place where from is found in text with to.

ArgumentTypeMeaning
textSTRINGthe text
fromSTRINGthe text to find (upper and lower case must match)
toSTRINGthe new text; '' removes from

Example

SELECT replace('a-b-c', '-', '/') AS a, replace('City Bank', 'Bank', 'Bank Limited') AS b, replace('City', 'city', 'x') AS case_matters, replace('CITY', '', 'x') AS empty_from;

Result:

a (STRING)b (STRING)case_matters (STRING)empty_from (STRING)
a/b/cCity Bank LimitedCityCITY

(1 row)

Example: Turn a price with commas into a number

SELECT CAST(replace('1,234,567.50', ',', '') AS DOUBLE) AS amount;

Result:

amount (DOUBLE)
1234567.5

(1 row)

split_part

Syntax:

split_part(text, separator, n)

Splits the text at every separator and gives part number n. 1 is the first part, -1 is the last part.

ArgumentTypeMeaning
textSTRINGthe text to split
separatorSTRINGthe text between the parts (one or more characters)
nwhole numberthe part: 1 first, 2 second, -1 last, -2 second last. 0 is an error

Example

SELECT split_part('2082/83', '/', 1) AS a, split_part('2082/83', '/', -1) AS last, split_part('a,b', ',', 5) AS missing;

Result:

a (STRING)last (STRING)missing (STRING)
208283

(1 row)

Example: The domain of each user's email

Setup:

CREATE TABLE app_users (id INT PRIMARY KEY AUTO, email STRING NOT NULL);
INSERT INTO app_users (email) VALUES ('ram@example.com'), ('sita@mail.com.np'), ('hari@example.com');
SELECT split_part(email, '@', 2) AS domain, count(*) AS users FROM app_users GROUP BY split_part(email, '@', 2) ORDER BY domain;

Result:

domain (STRING)users (LONG)
example.com2
mail.com.np1

(2 rows)

Example: Part number 0 does not exist (shows an error)

SELECT split_part('2082/83', '/', 0);

Result:

Error: line 1, column 8: split_part: the field number must not be 0 (1 = first, -1 = last)

strpos

Syntax:

strpos(text, part)

Where part first starts in text, as a character number (1 = first). 0 when it is not there.

ArgumentTypeMeaning
textSTRINGthe text to search in
partSTRINGthe text to find (case must match)

Example

SELECT strpos('CITY', 'IT') AS a, strpos('नेपाल बैंक', 'बैंक') AS nepali, strpos('CITY', 'x') AS not_found, strpos('City', 'cit') AS case_matters;

Result:

a (LONG)nepali (LONG)not_found (LONG)case_matters (LONG)
2700

(1 row)

Example: The user name before the @ of an email

SELECT email, left(email, strpos(email, '@') - 1) AS name
FROM (SELECT 'ram.sharma@example.com' AS email UNION ALL SELECT 'sita@mail.com.np') AS e;

Result:

email (STRING)name (STRING)
ram.sharma@example.comram.sharma
sita@mail.com.npsita

(2 rows)

position

Syntax:

position(part IN text)
position(part, text)

Where part first starts in text, as a character number (1 = first). 0 when it is not there. The same as strpos(text, part).

ArgumentTypeMeaning
partSTRINGthe text to find (case must match)
textSTRINGthe text to search in

Example

SELECT position('बैंक' IN 'नेपाल बैंक') AS nepali, position('TY' IN 'CITY') AS a, position('TY', 'CITY') AS b, position('x' IN 'CITY') AS not_found;

Result:

nepali (LONG)a (LONG)b (LONG)not_found (LONG)
7330

(1 row)

starts_with

Syntax:

starts_with(text, prefix)

true when the text begins with prefix.

ArgumentTypeMeaning
textSTRINGthe text
prefixSTRINGthe start to look for (case must match)

Example

SELECT starts_with('CITY', 'CI') AS a, starts_with('city', 'CI') AS case_matters, starts_with('CITY', '') AS empty;

Result:

a (BOOL)case_matters (BOOL)empty (BOOL)
truefalsetrue

(1 row)

Example: Companies whose symbol starts with N (sample data: sample)

SELECT symbol, name FROM securities WHERE starts_with(symbol, 'N') ORDER BY symbol;

Result:

symbol (SYMBOL)name (STRING)

(0 rows)

ends_with

Syntax:

ends_with(text, suffix)

true when the text ends with suffix.

ArgumentTypeMeaning
textSTRINGthe text
suffixSTRINGthe end to look for (case must match)

Example

SELECT ends_with('CITY', 'TY') AS a, ends_with('CITY', 'ty') AS case_matters;

Result:

a (BOOL)case_matters (BOOL)
truefalse

(1 row)

Example: Users with an email address in Nepal (.np)

Setup:

CREATE TABLE app_users (id INT PRIMARY KEY AUTO, email STRING NOT NULL);
INSERT INTO app_users (email) VALUES ('ram@example.com'), ('sita@mail.com.np'), ('hari@northwind.example.com');
SELECT id, email FROM app_users WHERE ends_with(lower(email), '.np') ORDER BY id;

Result:

id (INT)email (STRING)
2sita@mail.com.np

(1 row)

lpad

Syntax:

lpad(text, length)
lpad(text, length, fill)

Makes the text length characters long by adding fill on the left. When the text is longer, it is cut to length.

ArgumentTypeMeaning
textSTRING (a number is turned into text)the text
lengthwhole numberthe length you want, in characters (at most 10 000 000)
fillSTRINGwhat to add, repeated as needed; default one space

Example

SELECT lpad('7', 3, '0') AS a, '[' || lpad('5', 3) || ']' AS spaces, lpad('ab', 7, 'xy') AS b, lpad('CITY', 3) AS cut, lpad('न', 3, 'क') AS nepali;

Result:

a (STRING)spaces (STRING)b (STRING)cut (STRING)nepali (STRING)
007[ 5]xyxyxabCITककन

(1 row)

Example: Invoice numbers with leading zeros

Setup:

CREATE TABLE invoices (id INT PRIMARY KEY AUTO, amount DECIMAL(2));
INSERT INTO invoices (amount) VALUES (1500.00), (250.50), (99999.99);
SELECT 'INV-2082-' || lpad(id, 5, '0') AS invoice_no, amount FROM invoices ORDER BY id;

Result:

invoice_no (STRING)amount (DECIMAL(2))
INV-2082-000011500.00
INV-2082-00002250.50
INV-2082-0000399999.99

(3 rows)

Example: The length has a limit (shows an error)

SELECT lpad('a', 20000000);

Result:

Error: line 1, column 8: lpad: the length is larger than 10000000

rpad

Syntax:

rpad(text, length)
rpad(text, length, fill)

Makes the text length characters long by adding fill on the right. When the text is longer, it is cut to length.

ArgumentTypeMeaning
textSTRING (a number is turned into text)the text
lengthwhole numberthe length you want, in characters (at most 10 000 000)
fillSTRINGwhat to add, repeated as needed; default one space

Example

SELECT rpad('CITY', 8, '.') AS a, rpad('CITY', 3) AS cut, '[' || rpad('COAST', 6) || ']' AS spaces;

Result:

a (STRING)cut (STRING)spaces (STRING)
CITY....CIT[COAST ]

(1 row)

Example: A simple fixed-width price list (sample data: sample)

SELECT rpad(symbol, 8, '.') || lpad(close, 8) AS line
FROM ochl_day
WHERE time = '2026-09-09'
ORDER BY symbol;

Result:

line (STRING)
CITY.... 504.6
COAST... 380.1
VOLT.... 187.3

(3 rows)

repeat

Syntax:

repeat(text, n)

The text written n times one after another.

ArgumentTypeMeaning
textSTRINGthe text to repeat
nwhole numberhow many times; 0 or less gives ''

Example

SELECT repeat('ab', 3) AS a, repeat('नम', 2) AS nepali, repeat('-', 0) AS zero;

Result:

a (STRING)nepali (STRING)zero (STRING)
abababनमनम

(1 row)

Example: A text bar chart of the CITY close price (sample data: sample)

SELECT time, close, repeat('#', floor((close - 500) / 2)) AS bar
FROM ochl_day
WHERE symbol = 'CITY'
ORDER BY time
LIMIT 6;

Result:

time (TIMESTAMP)close (DOUBLE)bar (STRING)
2025-12-28T00:00:00.000Z542.2#####################
2025-12-29T00:00:00.000Z539.7###################
2025-12-30T00:00:00.000Z539.3###################
2025-12-31T00:00:00.000Z542.4#####################
2026-08-23T00:00:00.000Z507.9###
2026-08-24T00:00:00.000Z510.3#####

(6 rows)

reverse

Syntax:

reverse(text)

The characters of the text in the opposite order: reverse('CITY') is YTIC.

ArgumentTypeMeaning
textSTRING (or BYTES)the text

Example

SELECT reverse('CITY') AS a, reverse('12345') AS b, reverse('नेपाल') AS nepali;

Result:

a (STRING)b (STRING)nepali (STRING)
YTIC54321लापेन

(1 row)

concat

Syntax:

concat(value, value, ...)

Joins the values into one text. NULL values are skipped. Numbers, dates and times are turned into text first.

ArgumentTypeMeaning
valueany type1 to 64 values to join

Example

SELECT concat('CITY', '-', 2082) AS a, concat('a', NULL, 'b') AS null_skipped, concat(NULL) AS all_null, concat('Close: ', 512.5) AS b;

Result:

a (STRING)null_skipped (STRING)all_null (STRING)b (STRING)
CITY-2082abClose: 512.5

(1 row)

Example: Full name when the middle name is missing

Setup:

CREATE TABLE app_users (id INT PRIMARY KEY AUTO, first_name STRING, middle_name STRING, last_name STRING);
INSERT INTO app_users (first_name, middle_name, last_name) VALUES ('Ram', 'Bahadur', 'Thapa'), ('Sita', NULL, 'Sharma');
SELECT id,
       concat(first_name, ' ', middle_name, ' ', last_name) AS with_concat,
       first_name || ' ' || middle_name || ' ' || last_name AS with_pipes
FROM app_users ORDER BY id;

Result:

id (INT)with_concat (STRING)with_pipes (STRING)
1Ram Bahadur ThapaRam Bahadur Thapa
2Sita SharmaNULL

(2 rows)

concat_ws

Syntax:

concat_ws(separator, value, value, ...)

Joins the values with separator between them. NULL values are skipped, and they get no separator. "ws" means "with separator".

ArgumentTypeMeaning
separatorSTRINGthe text put between two values
valueany type0 to 63 values to join

Example

SELECT concat_ws(', ', 'a', NULL, 'b') AS a, concat_ws('/', 2082, 83) AS fiscal_year, concat_ws(NULL, 'a', 'b') AS null_separator;

Result:

a (STRING)fiscal_year (STRING)null_separator (STRING)
a, b2082/83NULL

(1 row)

Example: The full name from the example above, without double spaces

Setup:

CREATE TABLE app_users (id INT PRIMARY KEY AUTO, first_name STRING, middle_name STRING, last_name STRING);
INSERT INTO app_users (first_name, middle_name, last_name) VALUES ('Ram', 'Bahadur', 'Thapa'), ('Sita', NULL, 'Sharma');
SELECT id, concat_ws(' ', first_name, middle_name, last_name) AS full_name FROM app_users ORDER BY id;

Result:

id (INT)full_name (STRING)
1Ram Bahadur Thapa
2Sita Sharma

(2 rows)

format

Syntax:

format(text, value, value, ...)

Fills the places in text with the values, as PostgreSQL does. Its main use is SQL text for EXECUTE in a procedure.

PlacePuts inA NULL value
%sthe value as textnothing (empty text)
%Ia table or column name, in double quotes when neededan error
%La value in single quotes, quotes inside doubledNULL (no quotes)
%%one %
%2$sthe 2nd value (any place type); the next place takes the 3rd
%10s, %-10sat least 10 characters, filled with spaces on the left (or right with -)

Example

SELECT format('%s has %s rows', 'trades', 120) AS plain,
       format('SELECT * FROM %I WHERE symbol = %L', 'Daily Prices', 'it''s') AS safe_sql,
       format('[%-6s][%6s][%L]', 'ab', 'cd', NULL) AS widths;

Result:

plain (STRING)safe_sql (STRING)widths (STRING)
trades has 120 rowsSELECT * FROM "Daily Prices" WHERE symbol = 'it''s'[ab ][ cd][NULL]

(1 row)

Example: A NULL cannot be a name (shows an error)

SELECT format('SELECT * FROM %I', NULL);

Result:

Error: line 1, column 8: format: %I of format() got NULL: a NULL cannot be a table or column name

quote_ident

Syntax:

quote_ident(name)

The name as it can be written in SQL: as it is when it is all small letters, digits and _ and not a reserved word, otherwise in double quotes (with " doubled). quote_ident('close') is close; quote_ident('Close') is "Close".

quote_literal, quote_nullable

Syntax:

quote_literal(value)
quote_nullable(value)

The value as SQL text in single quotes, with every ' doubled: quote_literal('it''s') is 'it''s'. A number is quoted too.

Example

SELECT quote_ident('close') AS a, quote_ident('Daily Prices') AS b, quote_literal('O''Brien') AS c,
       quote_literal(42) AS d, quote_nullable(NULL) AS e;

Result:

a (STRING)b (STRING)c (STRING)d (STRING)e (STRING)
close"Daily Prices"'O''Brien''42'NULL

(1 row)

Example: One CSV line per trading day (sample data: sample)

SELECT concat_ws(',', symbol, open, high, low, close) AS csv_line
FROM ochl_day
WHERE symbol = 'COAST'
ORDER BY time
LIMIT 3;

Result:

csv_line (STRING)
COAST,420.3,426.6,417.6,424.8
COAST,425.9,428.9,421.2,424.2
COAST,423.6,426.1,420.1,423

(3 rows)

|| (join text)

Syntax:

text || text

Joins two values into one text: 'CITY' || '-' || 2082 is CITY-2082. A number or date on one side is turned into text.

OperandTypeMeaning
left, rightany typethe two values to join

Example

SELECT 'CITY' || '-' || 2082 AS a, 'Close: ' || 512.5 AS b, 'a' || NULL AS with_null, 'total ' || (1 + 2) AS brackets;

Result:

a (STRING)b (STRING)with_null (STRING)brackets (STRING)
CITY-2082Close: 512.5NULLtotal 3

(1 row)

Example: A link to each news article

Setup:

CREATE TABLE news (id LONG PRIMARY KEY AUTO, title STRING NOT NULL, symbol STRING);
INSERT INTO news (title, symbol) VALUES ('City Bank profit rises 18%', 'CITY'), ('Market index closes at 2,840', NULL);
SELECT id, '/news/' || id || '-' || lower(replace(left(title, 20), ' ', '-')) AS url,
       'Stock: ' || symbol AS stock_line,
       'Stock: ' || coalesce(symbol, 'market') AS fixed
FROM news ORDER BY id;

Result:

id (LONG)url (STRING)stock_line (STRING)fixed (STRING)
1/news/1-city-bank-profit-risStock: CITYStock: CITY
2/news/2-market-index-closes-NULLStock: market

(2 rows)

Example: Without brackets, + is done after || (shows an error)

SELECT 'total ' || 1 + 2;

Result:

Error: line 1, column 22: 'total 1' and '2' are not both numbers

initcap

Syntax:

initcap(text)

Every word gets a capital first letter and small letters after it: initcap('city bank limited') is City Bank Limited.

ArgumentTypeMeaning
textSTRING (a number is turned into text)the text to change

Example: Tidy up a name a user typed

SELECT initcap('city bank limited') AS company,
       initcap('RAM BAHADUR SHRESTHA') AS person,
       initcap('ram-bahadur kc') AS with_hyphen,
       initcap(NULL) AS nothing;

Result:

company (STRING)person (STRING)with_hyphen (STRING)nothing (STRING)
City Bank LimitedRam Bahadur ShresthaRam-Bahadur KcNULL

(1 row)

Example: Company names in title case (sample data: sample)

SELECT symbol, name, initcap(lower(name)) AS title_case
FROM securities
ORDER BY symbol;

Result:

symbol (SYMBOL)name (STRING)title_case (STRING)
ACMEAcme Investment CompanyAcme Investment Company
CITYCity Bank LimitedCity Bank Limited
COASTCoastal Bank LimitedCoastal Bank Limited
TELCONorthwind Telecom LimitedNorthwind Telecom Limited
VOLTVolt River Hydropower LimitedVolt River Hydropower Limited

(5 rows)

md5

Syntax:

md5(text)

The MD5 hash of the text: 32 lower-case hex digits. The same text always gives the same digits.

ArgumentTypeMeaning
textSTRING (a number or time is turned into text)the text to hash

Example: A short fingerprint for each daily candle (sample data: sample)

SELECT symbol, close, md5(symbol || ':' || CAST(time AS STRING)) AS row_key
FROM ochl_day
WHERE time IN '2026-09-10'
ORDER BY symbol;

Result:

symbol (SYMBOL)close (DOUBLE)row_key (STRING)
CITY504.98c227f18b2f287859fb2008492cc191a
COAST376.17e95ad0adf2f1015de2a7078a3a221c6
VOLT191.266b1f4d8c7af12a0fd60ade3702adfb1

(3 rows)

Example: The same text always gives the same digits

SELECT md5('CITY') AS a, md5('CITY') = md5('CITY') AS always_same, md5('') AS empty_text, md5(NULL) AS nothing;

Result:

a (STRING)always_same (BOOL)empty_text (STRING)nothing (STRING)
859214628431995197c0558f7b5f8ffctrued41d8cd98f00b204e9800998ecf8427eNULL

(1 row)

to_str

Syntax:

to_str(time, format)

Writes a time as text in the QuestDB format letters. QuestDB apps use this name; KDB's own name for the same job is to_char.

ArgumentTypeMeaning
timeTIMESTAMP, DATE, time text or millisecondsthe time to write
formatSTRINGthe pattern, see the table below
LettersGivesExample
yyyy, yyyear, 4 or 2 digits2026, 26
MM, MMMmonth number, month name09, Sep
ddday of the month10
HH, hhhour 0-23, hour 1-1205, 11
mm, ss, SSSminute, second, millisecond15, 00, 123
EEEweekday nameThu
aAM or PMAM
'text'text in single quotes is written as it is'at'

Example: Minute candles with a readable clock (sample data: sample)

SELECT to_str(time, 'yyyy-MM-dd') AS day,
       to_str(time, 'HH:mm') AS utc_clock,
       to_str(time + 20700000, 'HH:mm') AS nepal_clock,
       close
FROM ochl_minutes
WHERE symbol = 'CITY'
ORDER BY time
LIMIT 3;

Result:

day (STRING)utc_clock (STRING)nepal_clock (STRING)close (DOUBLE)
2026-09-0905:1511:00512.1
2026-09-0905:1611:01511.9
2026-09-0905:1711:02511.9

(3 rows)

Example: A long date for a report heading (sample data: sample)

SELECT to_str(time, 'EEE dd MMM yyyy') AS trading_day, symbol, close
FROM ochl_day
WHERE time IN '2026-09-10'
ORDER BY symbol;

Result:

trading_day (STRING)symbol (SYMBOL)close (DOUBLE)
Thu 10 Sep 2026CITY504.9
Thu 10 Sep 2026COAST376.1
Thu 10 Sep 2026VOLT191.2

(3 rows)

string_to_array

Syntax:

string_to_array(text, separator)
string_to_array(text, separator, null_text)

Cuts the text into a list at every separator. The PostgreSQL way to turn 'CITY,COAST' into a list of symbols.

ArgumentTypeMeaning
textSTRINGthe text to cut
separatorSTRINGthe text between the parts; NULL cuts into single characters
null_textSTRINGa part equal to this becomes NULL

Example: A watchlist typed as one line

SELECT string_to_array('CITY,COAST,VOLT', ',') AS symbols,
       cardinality(string_to_array('CITY,COAST,VOLT', ',')) AS how_many,
       string_to_array('CITY,,VOLT', ',', '') AS empty_part_is_null,
       string_to_array('MARKET', NULL) AS every_character;

Result:

symbols (TEXT[])how_many (LONG)empty_part_is_null (TEXT[])every_character (TEXT[])
["CITY","COAST","VOLT"]3["CITY",null,"VOLT"]["M","A","R","K","E","T"]

(1 row)

Example: Show the companies of a typed watchlist (sample data: sample)

SELECT symbol, name, sector
FROM securities
WHERE symbol IN (SELECT unnest(string_to_array('CITY,VOLT', ',')))
ORDER BY symbol;

Result:

symbol (SYMBOL)name (STRING)sector (STRING)
CITYCity Bank LimitedBanking
VOLTVolt River Hydropower LimitedEnergy

(2 rows)

string_to_table

Syntax:

string_to_table(text, separator)
string_to_table(text, separator, null_text)

The same cut as string_to_array, but one row per part instead of one list. Use it in FROM or in the SELECT list.

ArgumentTypeMeaning
textSTRINGthe text to cut
separatorSTRINGthe text between the parts; NULL cuts into single characters
null_textSTRINGa part equal to this becomes NULL

Example: A typed watchlist as rows

SELECT sym FROM string_to_table('CITY,COAST,VOLT', ',') AS t(sym);

Result:

sym (STRING)
CITY
COAST
VOLT

(3 rows)

ascii

Syntax:

ascii(text)

The number of the first character of the text (its Unicode code point). ascii('A') is 65, ascii('न') is 2344.

Example

SELECT ascii('A') AS a, ascii('é') AS e_accent, ascii('नेपाल') AS na, ascii('') AS empty;

Result:

a (LONG)e_accent (LONG)na (LONG)empty (LONG)
6523323440

(1 row)

chr

Syntax:

chr(number)

The character with this Unicode number: chr(65) is A, chr(2344) is न. The opposite of ascii.

Example

SELECT chr(65) AS a, chr(2344) AS na, chr(10) = E'\n' AS newline;

Result:

a (STRING)na (STRING)newline (BOOL)
Aनtrue

(1 row)

Example: 0 is not a character (shows an error)

SELECT chr(0);

Result:

Error: line 1, column 8: chr: null character not permitted

translate

Syntax:

translate(text, from, to)

Swaps single characters: each character of from becomes the character at the same place in to. A character of from with no partner in to is removed.

ArgumentTypeMeaning
textSTRINGthe text to change
fromSTRINGthe characters to find
toSTRINGwhat they become, place by place

Example

SELECT translate('12345', '143', 'ax') AS pg_example,
       translate('résumé', 'é', 'e') AS no_accents,
       translate('98-41-234567', '-', '') AS digits_only;

Result:

pg_example (STRING)no_accents (STRING)digits_only (STRING)
a2x5resume9841234567

(1 row)

overlay

Syntax:

overlay(text PLACING new_text FROM start)
overlay(text PLACING new_text FROM start FOR count)
overlay(text, new_text, start [, count])

Puts new_text into text at character start, in place of count characters. Without FOR, as many characters as new_text has are replaced.

Example

SELECT overlay('Txxxxas' PLACING 'hom' FROM 2 FOR 4) AS thomas,
       overlay('98XXXXXX45' PLACING '******' FROM 3) AS masked,
       overlay('abc' PLACING '-' FROM 2 FOR 0) AS inserted;

Result:

thomas (STRING)masked (STRING)inserted (STRING)
Thomas98******45a-bc

(1 row)

normalize

Syntax:

normalize(text)
normalize(text, NFC | NFD | NFKC | NFKD)

Brings text into one Unicode normal form. The same letter can be written two ways: á as one character, or as a followed by an accent mark. They look the same but do not compare equal until both are normalized.

FormWhat it does
NFC (the default)joins a letter and its marks into one character where Unicode has one
NFDtakes such characters apart: letter, then marks
NFKClike NFC, and turns look-alike characters into plain ones: fi → fi, ² → 2, ① → 1
NFKDlike NFD with the same look-alike rule

Example

SELECT normalize(U&'\0061\0301', NFC) = U&'\00E1' AS same_letter,
       length(normalize('á', NFD)) AS letters_nfd,
       normalize('file ²', NFKC) AS plain;

Result:

same_letter (BOOL)letters_nfd (LONG)plain (STRING)
true2file 2

(1 row)

U&'...' is PostgreSQL's way to write characters by number: \XXXX (4 hex digits) or \+XXXXXX (6), and \\ for a backslash.

to_ascii

Syntax:

to_ascii(text)
to_ascii(text, 'LATIN1')

The text with accents taken off, in plain ASCII: to_ascii('Karél') is Karel.

Example

SELECT to_ascii('Karél') AS a, to_ascii('Škoda Ørsted') AS b;

Result:

a (STRING)b (STRING)
KarelSkoda Orsted

(1 row)

bit_length

Syntax:

bit_length(text)

The size of the text in bits: 8 times octet_length. bit_length('jose') is 32; bit_length('न') is 24.

Example

SELECT bit_length('jose') AS english, bit_length('न') AS nepali_letter;

Result:

english (LONG)nepali_letter (LONG)
3224

(1 row)

to_hex

Syntax:

to_hex(number)

A whole number in hexadecimal (base 16), small letters: to_hex(255) is ff.

Example

SELECT to_hex(255) AS ff, to_hex(4096) AS big, to_hex(-1) AS minus_one;

Result:

ff (STRING)big (STRING)minus_one (STRING)
ff1000ffffffff

(1 row)

parse_ident

Syntax:

parse_ident(name)
parse_ident(name, strict)

Splits a qualified name like "SomeSchema".someTable into its parts, the PostgreSQL way: quotes are taken off, a name without quotes is made lower case, "" inside quotes is one quote.

Example

SELECT parse_ident('"SomeSchema".someTable') AS parts,
       parse_ident('market.Trades')[2] AS table_part;

Result:

parts (TEXT[])table_part (STRING)
["SomeSchema","sometable"]trades

(1 row)

to_char for numbers

Syntax:

to_char(number, format)

Writes a number as text with a picture of the digits, exactly as PostgreSQL does. (For times see to_char.)

CodeMeaning
9a digit; a blank when the number has no digit here
0a digit, 0 when the number has none (leading zeros)
. or Dthe decimal point
, or Gthe thousands separator (left out before the first digit)
FMno padding blanks and no trailing zeros
S, MI, PL, SGthe sign next to the number; - at that place; + at that place; + or - at that place
PRa negative number in angle brackets: <485>
Lthe money sign $
RN / rnRoman numerals (1 to 3999)
TH / ththe ordinal ending: 1st, 22nd, 13th
Vmultiplies by 10 for each 9 after it
EEEEscientific notation: 4.86e-04
"text"text as it is

Example

SELECT to_char(1234.5, 'FM999,999.00') AS money,
       to_char(-485, '999PR') AS bracket,
       to_char(7, 'FM000') AS padded,
       to_char(0.0004859, '9.99EEEE') AS sci,
       to_char(2026, 'FMRN') AS roman,
       to_char(22, 'FM99th') AS ordinal;

Result:

money (STRING)bracket (STRING)padded (STRING)sci (STRING)roman (STRING)ordinal (STRING)
1,234.50<485>0074.86e-04MMXXVI22nd

(1 row)

Example: Turnover in a report (sample data: sample)

SELECT symbol, to_char(sum(close * volume), 'FM999,999,999,990.00') AS turnover
FROM ochl_day
GROUP BY symbol
ORDER BY symbol
LIMIT 3;

Result:

symbol (SYMBOL)turnover (STRING)
CITY1,012,051,301.00
COAST640,748,179.00
VOLT326,540,767.00

(3 rows)