KDB knowledge

Conversion functions

Change a value from one type to another with CAST, ::, to_timestamp and to_date.

A value has a type: a number, a text, a time and so on. Sometimes a value has the wrong type for what you want to do. A price read from a text file is the text '512.50', not a number. CAST changes the type.

The rules are the same as when a value goes into a table column of that type (see column types). The entries "Into ..." below list them for each type.

Example: Prices, quantities and times that arrived as text

Setup:

CREATE TABLE price_import (line INT PRIMARY KEY, symbol STRING, price STRING, qty STRING, traded STRING, is_buy STRING);
INSERT INTO price_import VALUES
  (1, 'CITY', '512.50', '100', '2026-09-10T11:05:00+05:45', 'true'),
  (2, 'COAST',  '398',    '20',  '2026-09-10T13:00:00+05:45', 'false'),
  (3, 'VOLT', '184.0',  '50',  '2026-09-10T14:59:00+05:45', '1');
SELECT symbol,
       CAST(price AS DOUBLE) * CAST(qty AS LONG) AS amount,
       CAST(traded AS TIMESTAMP) AS traded_utc,
       is_buy::BOOL AS is_buy
FROM price_import
ORDER BY line;

Result:

symbol (STRING)amount (DOUBLE)traded_utc (TIMESTAMP)is_buy (BOOL)
CITY512502026-09-10T05:20:00.000Ztrue
COAST79602026-09-10T07:15:00.000Zfalse
VOLT92002026-09-10T09:14:00.000Ztrue

(3 rows)

The examples below also use this small accounting table. Money is kept in DECIMAL(2): an exact number with 2 places after the point.

Setup used by the examples below:

CREATE TABLE ledger (
  id      INT PRIMARY KEY,
  day     DATE,
  account STRING,
  amount  DECIMAL(2)
);
INSERT INTO ledger VALUES
  (1, '2026-09-01', 'Sales', 1250.00),
  (2, '2026-09-02', 'Sales', 899.99),
  (3, '2026-09-02', 'Rent', 1200.50);

CAST

Syntax:

CAST(value AS type)

Changes value into type.

ArgumentTypeMeaning
valueanythe value to change
typea type nameBOOL (BOOLEAN), BYTE, SHORT, INT (INTEGER), LONG (BIGINT), FLOAT, DOUBLE, DECIMAL(s), DATE, TIMESTAMP, SYMBOL, STRING (VARCHAR, TEXT), JSON (JSONB), BYTES (BYTEA, BLOB)

Example

SELECT CAST('512.5' AS DOUBLE) + 1 AS a,
       CAST(42 AS STRING) AS b,
       CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP) AS c,
       CAST('12.5' AS DECIMAL(2)) AS d,
       CAST(NULL AS INT) AS e;

Result:

a (DOUBLE)b (STRING)c (TIMESTAMP)d (DECIMAL(2))e (STRING)
513.5422026-09-10T05:15:00.000Z12.50NULL

(1 row)

Example: 13% VAT on each ledger line, as exact money

SELECT id, account, amount,
       CAST(round(amount * 0.13, 2) AS DECIMAL(2)) AS vat,
       amount * 0.13 AS vat_as_double
FROM ledger
ORDER BY id;

Result:

id (INT)account (STRING)amount (DECIMAL(2))vat (DECIMAL(2))vat_as_double (DECIMAL(4))
1Sales1250.00162.50162.5000
2Sales899.99117.00116.9987
3Rent1200.50156.07156.0650

(3 rows)

Example: Into a whole number: the fraction is rounded

SELECT CAST(5.5 AS INT) AS half_up, CAST(5.4 AS INT) AS down, CAST(-5.5 AS INT) AS negative;

Result:

half_up (LONG)down (LONG)negative (LONG)
65-6

(1 row)

Example: DECIMAL without a scale is DOUBLE

SELECT CAST('12.50' AS DECIMAL) AS as_double, CAST('12.50' AS DECIMAL(2)) AS exact_money;

Result:

as_double (DOUBLE)exact_money (DECIMAL(2))
12.512.50

(1 row)

:: (short cast)

Syntax:

value::type

The short way to write CAST(value AS type). '42'::INT is CAST('42' AS INT). It comes from PostgreSQL.

Example

SELECT '42'::INT + 1 AS a, 2 + 3::DOUBLE AS b, (2 + 3)::STRING AS c, '12.5'::DECIMAL(2) AS d, NULL::BOOL AS e;

Result:

a (LONG)b (DOUBLE)c (STRING)d (DECIMAL(2))e (STRING)
435512.50NULL

(1 row)

Example: Filter candles with a Nepal time written as text (sample data: sample)

SELECT time, symbol, close
FROM ochl_minutes
WHERE symbol = 'COAST'
  AND time >= '2026-09-10T11:00:00+05:45'::TIMESTAMP
  AND time <  '2026-09-10T11:03:00+05:45'::TIMESTAMP;

Result:

time (TIMESTAMP)symbol (SYMBOL)close (DOUBLE)
2026-09-10T05:15:00.000ZCOAST380
2026-09-10T05:16:00.000ZCOAST379.6
2026-09-10T05:17:00.000ZCOAST380.1

(3 rows)

Example: A length after VARCHAR is read and ignored

SELECT CAST('CITY' AS VARCHAR(10)) AS a, CAST('CITY' AS VARCHAR(3)) AS nothing_is_cut;

Result:

a (STRING)nothing_is_cut (STRING)
CITYCITY

(1 row)

to_timestamp

Syntax:

to_timestamp(value)

Makes a TIMESTAMP (a moment in time, stored in UTC) from time text, a DATE or a number of seconds.

ArgumentTypeMeaning
valuetext, DATE, TIMESTAMP or numbertime text like '2026-09-10T11:00:00+05:45', or seconds since 1970-01-01 UTC (a fraction is allowed)

Example

SELECT to_timestamp('2026-09-10T11:00:00+05:45') AS nepal_text,
       to_timestamp('2026-09-10') AS date_text,
       to_timestamp(1789020900) AS from_seconds,
       to_timestamp(1789020900.25) AS with_fraction,
       to_timestamp(1789020900000 / 1000.0) AS from_ms,
       to_timestamp(NULL) AS nothing;

Result:

nepal_text (TIMESTAMP)date_text (TIMESTAMP)from_seconds (TIMESTAMP)with_fraction (TIMESTAMP)from_ms (TIMESTAMP)nothing (STRING)
2026-09-10T05:15:00.000Z2026-09-10T00:00:00.000Z2026-09-10T06:15:00.000Z2026-09-10T06:15:00.250Z2026-09-10T06:15:00.000ZNULL

(1 row)

Example: App sign-up times sent as milliseconds

Setup:

CREATE TABLE app_signups (user_id INT PRIMARY KEY, name STRING, created_ms LONG);
INSERT INTO app_signups VALUES (1, 'Sita', 1788900300000), (2, 'Ram', 1788928200000), (3, 'Hari', 1789020900000);
SELECT user_id, name, created_ms, to_timestamp(created_ms / 1000.0) AS created, CAST(created_ms AS TIMESTAMP) AS same
FROM app_signups
ORDER BY user_id;

Result:

user_id (INT)name (STRING)created_ms (LONG)created (TIMESTAMP)same (TIMESTAMP)
1Sita17889003000002026-09-08T20:45:00.000Z2026-09-08T20:45:00.000Z
2Ram17889282000002026-09-09T04:30:00.000Z2026-09-09T04:30:00.000Z
3Hari17890209000002026-09-10T06:15:00.000Z2026-09-10T06:15:00.000Z

(3 rows)

Example: Text that is not a time (shows an error)

SELECT to_timestamp('10/09/2026');

Result:

Error: line 1, column 8: to_timestamp: argument 1 must be a time, got '10/09/2026'

to_date

Syntax:

to_date(value)

Makes a DATE (a day without a clock time) from time text, a TIMESTAMP or a number of milliseconds. It keeps the UTC date.

ArgumentTypeMeaning
valuetext, TIMESTAMP, DATE or whole numbera time, or milliseconds since 1970-01-01 UTC

Example

SELECT to_date('2026-09-10T20:00:00Z') AS a,
       to_date('2026-09-10T03:00:00+05:45') AS nepal_3am_is_utc_day_before,
       to_date(86400000) AS b,
       to_date(NULL) AS c;

Result:

a (DATE)nepal_3am_is_utc_day_before (DATE)b (DATE)c (STRING)
2026-09-102026-09-091970-01-02NULL

(1 row)

Example: Sign-ups per day: UTC date and Nepal date

Setup:

CREATE TABLE app_signups (user_id INT PRIMARY KEY, name STRING, created TIMESTAMP);
INSERT INTO app_signups VALUES
  (1, 'Sita', '2026-09-09T02:30:00+05:45'),
  (2, 'Ram',  '2026-09-09T10:15:00+05:45'),
  (3, 'Hari', '2026-09-09T15:45:00+05:45'),
  (4, 'Gita', '2026-09-10T12:00:00+05:45');
SELECT to_date(created) AS utc_day, count(*) AS signups
FROM app_signups GROUP BY to_date(created) ORDER BY utc_day;

SELECT to_date(created + 20700000) AS nepal_day, count(*) AS signups
FROM app_signups GROUP BY to_date(created + 20700000) ORDER BY nepal_day;

Result:

SELECT to_date(created) AS utc_day, count(*) AS signups FROM app_signups GROUP BY to_date(created) O

utc_day (DATE)signups (LONG)
2026-09-081
2026-09-092
2026-09-101

(3 rows)

SELECT to_date(created + 20700000) AS nepal_day, count(*) AS signups FROM app_signups GROUP BY to_da

nepal_day (DATE)signups (LONG)
2026-09-093
2026-09-101

(2 rows)

Example: true is not a time (shows an error)

SELECT to_date(TRUE);

Result:

Error: line 1, column 8: to_date: argument 1 must be a time, got 'true'

Into integers

Syntax:

CAST(value AS BYTE | SHORT | INT | INTEGER | LONG | BIGINT)

Whole numbers. The types differ only in size:

TypeSmallestBiggest
BYTE-127127
SHORT-3276732767
INT, INTEGER-21474836472147483647
LONG, BIGINT-92233720368547758079223372036854775807
FromResult
a whole numberthe same number, if it is in range
DOUBLErounded to the nearest whole number: 5.4 gives 5, 5.5 gives 6, -5.5 gives -6
DECIMAL(s)rounded the same way: 1.50 gives 2
texta number like '42', ' -7' or '5.5' (spaces before are allowed, spaces after are not); a fraction is rounded
TRUE / FALSE1 / 0
TIMESTAMPthe milliseconds since 1970-01-01, as PostgreSQL apps expect
DATE, JSON, BYTESerror

Example

SELECT CAST('42' AS INT) AS a, CAST(5.0 AS INT) AS b, CAST(TRUE AS INT) AS c,
       CAST(CAST('2.00' AS DECIMAL(2)) AS LONG) AS d, CAST(round(512.5) AS INT) AS e, CAST(-127 AS BYTE) AS f;

Result:

a (LONG)b (LONG)c (LONG)d (LONG)e (LONG)f (LONG)
42512513-127

(1 row)

Example: Shares per trade from text, and a time as milliseconds (sample data: sample)

SELECT transaction_id, symbol,
       CAST(quantity AS STRING) AS qty_text,
       CAST(CAST(quantity AS STRING) AS LONG) + 1 AS back_to_number,
       date - 0::TIMESTAMP AS date_ms
FROM trade_log
ORDER BY transaction_id
LIMIT 3;

Result:

transaction_id (LONG)symbol (SYMBOL)qty_text (STRING)back_to_number (LONG)date_ms (LONG)
100001TELCO100010011788912000000
100002CITY10111788912000000
100003CITY5005011788912000000

(3 rows)

Example: A fraction is rounded to the nearest whole number

SELECT CAST(512.5 AS INT) AS a, CAST(512.4 AS INT) AS b, CAST('5.5' AS INT) AS from_text;

Result:

a (LONG)b (LONG)from_text (LONG)
5135126

(1 row)

Example: Too big for BYTE (shows an error)

SELECT CAST(300 AS BYTE);

Result:

Error: line 1, column 8: cannot convert '300' to BYTE

Example: A TIMESTAMP gives its milliseconds; a DATE does not (shows an error)

SELECT CAST(CAST('2026-09-10' AS TIMESTAMP) AS LONG) AS milliseconds;
SELECT CAST(CAST('2026-09-10' AS DATE) AS LONG);

Result:

milliseconds (LONG)
1788998400000

(1 row)

Error: line 2, column 8: cannot convert '2026-09-10' to LONG

Into DOUBLE and FLOAT

Syntax:

CAST(value AS DOUBLE | FLOAT)

Numbers with a fraction. DOUBLE keeps about 15 digits. FLOAT is smaller and keeps about 7 digits.

FromResult
any number (LONG, DOUBLE, DECIMAL)the number
texta number like '512.5', '-3' or '1e3'
BOOL, times, JSON, BYTESerror

Example

SELECT CAST('512.5' AS DOUBLE) AS a, CAST('1e3' AS DOUBLE) AS b,
       CAST(CAST('1.25' AS DECIMAL(2)) AS DOUBLE) AS c, CAST(0.1 AS FLOAT) AS d, 0.1 + 0.2 AS e;

Result:

a (DOUBLE)b (DOUBLE)c (DOUBLE)d (DOUBLE)e (DOUBLE)
512.510001.250.1000000014901160.3

(1 row)

Example: Ledger amounts as DOUBLE for a chart

SELECT day, account, amount, CAST(amount AS DOUBLE) AS amount_double
FROM ledger
ORDER BY id;

Result:

day (DATE)account (STRING)amount (DECIMAL(2))amount_double (DOUBLE)
2026-09-01Sales1250.001250
2026-09-02Sales899.99899.99
2026-09-02Rent1200.501200.5

(3 rows)

Example: Text that is not a number (shows an error)

SELECT CAST('$512' AS DOUBLE);

Result:

Error: line 1, column 8: cannot convert '$512' to DOUBLE

Into DECIMAL(s)

Syntax:

CAST(value AS DECIMAL(scale))

An exact number with scale places after the point. DECIMAL(2) is right for dollars and cents.

FromResult
a whole number7 becomes 7.00
DECIMALthe same value with the new scale, if no digit is lost
DOUBLEthe value rounded to scale places: 12.345 gives 12.35 for DECIMAL(2)
texta number like '1250.75'; more places than scale are rounded
BOOL, times, JSON, BYTESerror
PartMeaning
scaleDECIMAL(s): 0 to 18 (18 digits in all). NUMERIC(p, s): 0 to 38, p up to 38 digits

Example

SELECT CAST(7 AS DECIMAL(2)) AS a, CAST('1250.75' AS DECIMAL(2)) AS b, CAST(1500.256 AS DECIMAL(3)) AS c,
       CAST(0.1 + 0.2 AS DECIMAL(2)) AS d, CAST(CAST('1.5' AS DECIMAL(1)) AS DECIMAL(3)) AS e;

Result:

a (DECIMAL(2))b (DECIMAL(2))c (DECIMAL(3))d (DECIMAL(2))e (DECIMAL(3))
7.001250.751500.2560.301.500

(1 row)

Example: Month report: totals and average per account, exact to the cent

SELECT account,
       sum(amount) AS total,
       CAST(round(avg(amount), 2) AS DECIMAL(2)) AS average,
       count(*) AS lines
FROM ledger
WHERE day IN '2026-09'
GROUP BY account
ORDER BY account;

Result:

account (STRING)total (DECIMAL(2))average (DECIMAL(2))lines (LONG)
Rent1200.501200.501
Sales2149.991075.002

(2 rows)

Example: Too many places are rounded, not refused

SELECT CAST(12.345 AS DECIMAL(2)) AS rounded_up, CAST(12.344 AS DECIMAL(2)) AS rounded_down,
       CAST('1250.756' AS DECIMAL(2)) AS from_text;

Result:

rounded_up (DECIMAL(2))rounded_down (DECIMAL(2))from_text (DECIMAL(2))
12.3512.341250.76

(1 row)

Example: NUMERIC(24,2) holds 24 digits

SELECT CAST(123456789012345678.12 AS NUMERIC(24,2)) AS big, CAST(1 AS NUMERIC(20,2)) / 3 AS third;

Result:

big (DECIMAL(38,2))third (DECIMAL(38,20))
123456789012345678.120.33333333333333333333

(1 row)

Into TIMESTAMP

Syntax:

CAST(value AS TIMESTAMP)

A moment in time, stored as milliseconds since 1970-01-01 UTC. KDB always shows it in UTC, like 2026-09-10T05:15:00.000Z.

FromResult
time text'2026-09-10', '2026-09-10 11:00', '2026-09-10T11:00:00.123', with an optional Z, +05:45 or +0545 at the end. No zone means UTC
DATEmidnight UTC of that day
a whole numberthat many milliseconds after 1970-01-01 UTC
DOUBLE, BOOL, JSON, BYTESerror

Example

SELECT CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP) AS nepal_11am,
       CAST('2026-09-10 11:00' AS TIMESTAMP) AS utc_11am,
       CAST(CAST('2026-09-10' AS DATE) AS TIMESTAMP) AS from_date,
       CAST(0 AS TIMESTAMP) AS zero,
       CAST('2026-09-10T11:00:00.123456+0545' AS TIMESTAMP) AS micro_cut;

Result:

nepal_11am (TIMESTAMP)utc_11am (TIMESTAMP)from_date (TIMESTAMP)zero (TIMESTAMP)micro_cut (TIMESTAMP)
2026-09-10T05:15:00.000Z2026-09-10T11:00:00.000Z2026-09-10T00:00:00.000Z1970-01-01T00:00:00.000Z2026-09-10T05:15:00.123Z

(1 row)

Example: Market open and close (Nepal time) as UTC times (sample data: sample)

SELECT symbol, count(*) AS minutes, min(time) AS first_minute, max(time) AS last_minute
FROM ochl_minutes
WHERE time >= CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP)
  AND time <  CAST('2026-09-10T15:00:00+05:45' AS TIMESTAMP)
GROUP BY symbol
ORDER BY symbol;

Result:

symbol (SYMBOL)minutes (LONG)first_minute (TIMESTAMP)last_minute (TIMESTAMP)
CITY2402026-09-10T05:15:00.000Z2026-09-10T09:14:00.000Z
COAST2362026-09-10T05:15:00.000Z2026-09-10T09:14:00.000Z

(2 rows)

Example: Day/month/year order is not read (shows an error)

SELECT CAST('10/09/2026' AS TIMESTAMP);

Result:

Error: line 1, column 8: cannot convert '10/09/2026' to TIMESTAMP

Into DATE

Syntax:

CAST(value AS DATE)

A day without a clock time, shown like 2026-09-10.

FromResult
date text'2026-09-10'
time textthe UTC date of that time
TIMESTAMPthe UTC date
numbers, BOOL, JSON, BYTESerror (use to_date for milliseconds)

Example

SELECT CAST('2026-09-10' AS DATE) AS a,
       CAST('2026-09-10T03:00:00+05:45' AS DATE) AS nepal_early_morning,
       CAST(CAST('2026-09-10T23:59:00Z' AS TIMESTAMP) AS DATE) AS b,
       CAST('2026-09-10' AS DATE) + 1 AS next_day;

Result:

a (DATE)nepal_early_morning (DATE)b (DATE)next_day (DATE)
2026-09-102026-09-092026-09-102026-09-11

(1 row)

Example: Trades per day from the trade log (sample data: sample)

SELECT CAST(date AS DATE) AS trade_day, count(*) AS trades, sum(quantity) AS shares
FROM trade_log
GROUP BY CAST(date AS DATE)
ORDER BY trade_day;

Result:

trade_day (DATE)trades (LONG)shares (LONG)
2026-09-0983730
2026-09-10244930

(2 rows)

Example: There is no 30 February (shows an error)

SELECT CAST('2026-02-30' AS DATE);

Result:

Error: line 1, column 8: cannot convert '2026-02-30' to DATE

Example: CAST into DATE does not take a number (shows an error)

SELECT CAST(20260910 AS DATE);

Result:

Error: line 1, column 8: cannot convert '20260910' to DATE

Into BOOL

Syntax:

CAST(value AS BOOL | BOOLEAN)

true or false.

FromResult
TRUE / FALSEthe same
the whole numbers 1 / 0true / false; any other number is an error
text'true', 't', '1' are true; 'false', 'f', '0' are false (any letter case)
DOUBLE, times, JSON, BYTESerror

Example

SELECT CAST(1 AS BOOL) AS a, CAST(0 AS BOOL) AS b, CAST('TRUE' AS BOOL) AS c, CAST('f' AS BOOL) AS d, '1'::BOOLEAN AS e;

Result:

a (BOOL)b (BOOL)c (BOOL)d (BOOL)e (BOOL)
truefalsetruefalsetrue

(1 row)

Example: A yes/no column from an import (shows an error)

SELECT CAST('yes' AS BOOL);

Result:

Error: line 1, column 8: cannot convert 'yes' to BOOL

Example: Map yes/no with CASE, then it works

SELECT answer, CASE lower(answer) WHEN 'yes' THEN TRUE WHEN 'no' THEN FALSE END AS agreed
FROM (SELECT 'Yes' AS answer UNION ALL SELECT 'no') t;

Result:

answer (STRING)agreed (BOOL)
Yestrue
nofalse

(2 rows)

Into STRING and SYMBOL

Syntax:

CAST(value AS STRING | VARCHAR | TEXT | SYMBOL)

Text. Every value can become text.

FromText
whole number42
DOUBLEthe shortest form that reads back the same: 512.5, 0.30000000000000004
DECIMAL(s)with all s places: 1.50
BOOLtrue / false
TIMESTAMPUTC in ISO form: 2026-09-10T05:15:00.000Z
DATE2026-09-10
JSONthe JSON text; a JSON string keeps its quotes ("text")
BYTEShex with \x in front: \x4e41

Example

SELECT CAST(42 AS STRING) AS a, CAST(512.5 AS TEXT) AS b, CAST(CAST('1.50' AS DECIMAL(2)) AS VARCHAR) AS c,
       CAST(TRUE AS STRING) AS d, CAST(CAST('2026-09-10T11:00:00+05:45' AS TIMESTAMP) AS STRING) AS e,
       CAST(0.1 + 0.2 AS STRING) AS f;

Result:

a (STRING)b (STRING)c (STRING)d (STRING)e (STRING)f (STRING)
42512.51.50true2026-09-10T05:15:00.000Z0.30000000000000004

(1 row)

Example: A label for a chart: symbol, date and close (sample data: sample)

SELECT symbol || ' ' || CAST(CAST(time AS DATE) AS STRING) || ': ' || CAST(close AS STRING) AS label
FROM ochl_day
WHERE symbol = 'VOLT'
ORDER BY time DESC
LIMIT 3;

Result:

label (STRING)
VOLT 2026-09-10: 191.2
VOLT 2026-09-09: 187.3
VOLT 2026-09-08: 182.4

(3 rows)

Example: JSON and BYTES as text

SELECT CAST(CAST('{"a": 1}' AS JSON) AS STRING) AS json_object,
       CAST(CAST('"text"' AS JSON) AS STRING) AS json_string,
       CAST(CAST('NA' AS BYTES) AS STRING) AS bytes;

Result:

json_object (STRING)json_string (STRING)bytes (STRING)
{"a":1}"text"\x4e41

(1 row)

Into JSON

Syntax:

CAST(value AS JSON | JSONB)

A JSON document (a text format for data, like {"name": "Sita", "tags": [1, 2]}). KDB checks it and stores it without extra spaces.

FromResult
textparsed as JSON; bad JSON is an error that says where the problem is
numbers, DECIMALa JSON number: 5, 1.50
BOOLtrue / false
TIMESTAMP, DATE, BYTESa JSON string with their text: "2026-09-10"

Example

SELECT CAST('{"symbol": "CITY", "levels": [500, 520]}' AS JSON) AS a,
       CAST(5 AS JSON) AS b, CAST(TRUE AS JSONB) AS c,
       CAST(CAST('2026-09-10' AS DATE) AS JSON) AS d,
       CAST('null' AS JSON) AS json_null, CAST('null' AS JSON) IS NULL AS is_sql_null;

Result:

a (JSON)b (JSON)c (JSON)d (JSON)json_null (JSON)is_sql_null (BOOL)
{"symbol":"CITY","levels":[500,520]}5true"2026-09-10"NULLfalse

(1 row)

Example: App settings saved as JSON text

Setup:

CREATE TABLE user_settings (user_id INT PRIMARY KEY, settings STRING);
INSERT INTO user_settings VALUES (1, '{ "theme": "dark",  "alerts": ["CITY", "COAST"] }'), (2, '{"theme": "light", "alerts": []}');
SELECT user_id, CAST(settings AS JSON) AS settings_json
FROM user_settings
ORDER BY user_id;

Result:

user_id (INT)settings_json (JSON)
1{"theme":"dark","alerts":["CITY","COAST"]}
2{"theme":"light","alerts":[]}

(2 rows)

Example: Keys need double quotes (shows an error)

SELECT CAST('{theme: "dark"}' AS JSON);

Result:

Error: line 1, column 8: cannot convert '{theme: "dark"}' to JSON: not valid JSON: expected a key in double quotes at character 2 (near 'theme: "dark...')

Into BYTES

Syntax:

CAST(value AS BYTES | BYTEA | BLOB)

Raw bytes, shown as hex with \x in front (\x0a0b).

FromResult
text that starts with \xread as hex digits: '\x4e41' is the two bytes 4e and 41
other textits UTF-8 bytes: 'NA' is \x4e41; a Nepali letter is 3 bytes
X'0A0B'already bytes
numbers, BOOL, times, JSONerror

Example

SELECT CAST('\x4e41' AS BYTES) AS from_hex, CAST('CITY' AS BYTEA) AS from_text,
       CAST(X'0A0B' AS BLOB) AS literal, CAST('नेपाल' AS BYTES) AS nepali, length(CAST('नेपाल' AS BYTES)) AS byte_count;

Result:

from_hex (BYTES)from_text (BYTES)literal (BYTES)nepali (BYTES)byte_count (LONG)
\x4e41\x43495459\x0a0b\xe0a4a8e0a587e0a4aae0a4bee0a4b215

(1 row)

Example: Bad hex digits (shows an error)

SELECT CAST('\xZZ' AS BYTES);

Result:

Error: line 1, column 8: cannot convert '\xZZ' to BYTES: '\xZZ' is not hex bytes; write them like '\x0a0b' or X'0A0B'

Example: A number is not bytes (shows an error)

SELECT CAST(5 AS BYTES);

Result:

Error: line 1, column 8: cannot convert '5' to BYTES: expected bytes like X'0A0B' or '\x0a0b', got LONG 5