Conversion functions
Change a value from one type to another with CAST, ::, to_timestamp and to_date.
- Category: Functions — conversion
- Keywords: convert, conversion, type conversion, change type, cast, ::, to number, to text, parse number, parse date, epoch, unix time, milliseconds, cannot convert, INTEGER, BIGINT, BOOLEAN, VARCHAR, TEXT, JSONB, BYTEA, BLOB, FLOAT, SHORT, BYTE
- See also: Column types, Date and time functions (to_char), Conditional and NULL functions (coalesce), Math functions (round), JSON functions, Operators
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.
CAST(x AS type)andx::typedo the same thing.to_timestamp(x)turns text or seconds into a time;to_date(x)turns text or milliseconds into a date.- KDB never guesses. When a value does not fit the new type, you get an error like
cannot convert '5.5' to INT. It does not round or cut the value for you. NULLstaysNULLin every conversion.
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) |
|---|---|---|---|
| CITY | 51250 | 2026-09-10T05:20:00.000Z | true |
| COAST | 7960 | 2026-09-10T07:15:00.000Z | false |
| VOLT | 9200 | 2026-09-10T09:14:00.000Z | true |
(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.
| Argument | Type | Meaning |
|---|---|---|
value | any | the value to change |
type | a type name | BOOL (BOOLEAN), BYTE, SHORT, INT (INTEGER), LONG (BIGINT), FLOAT, DOUBLE, DECIMAL(s), DATE, TIMESTAMP, SYMBOL, STRING (VARCHAR, TEXT), JSON (JSONB), BYTES (BYTEA, BLOB) |
- Returns: a value of
type. - NULL:
CAST(NULL AS type)isNULL. - Notes:
- When the value does not fit, the error is
cannot convert '...' to TYPE. For JSON and BYTES the message also says what is wrong. DECIMALwithout a scale meansDOUBLE. WriteCAST(x AS DECIMAL(2))when you want exact money. A length likeVARCHAR(10)orCHAR(3)is read and ignored: nothing is cut.- Many things need no
CAST. Text compared with a time is read as a time (time >= '2026-09-01').||joins numbers as text ('CITY' || 1). - To turn a time into formatted text, use to_char, not
CAST.
- When the value does not fit, the error is
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.5 | 42 | 2026-09-10T05:15:00.000Z | 12.50 | NULL |
(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)) |
|---|---|---|---|---|
| 1 | Sales | 1250.00 | 162.50 | 162.5000 |
| 2 | Sales | 899.99 | 117.00 | 116.9987 |
| 3 | Rent | 1200.50 | 156.07 | 156.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) |
|---|---|---|
| 6 | 5 | -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.5 | 12.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.
- Returns: a value of
type, as with CAST. - NULL:
NULL::INTisNULL. - Notes:
::holds on to the value right before it, more tightly than any operator.2 + 3::DOUBLEchanges only3. Put( )around a longer expression:(2 + 3)::STRING.
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) |
|---|---|---|---|---|
| 43 | 5 | 5 | 12.50 | NULL |
(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.000Z | COAST | 380 |
| 2026-09-10T05:16:00.000Z | COAST | 379.6 |
| 2026-09-10T05:17:00.000Z | COAST | 380.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) |
|---|---|
| CITY | CITY |
(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.
| Argument | Type | Meaning |
|---|---|---|
value | text, DATE, TIMESTAMP or number | time text like '2026-09-10T11:00:00+05:45', or seconds since 1970-01-01 UTC (a fraction is allowed) |
- Returns:
TIMESTAMP. - NULL:
NULLin,NULLout. - Notes:
- A number means seconds, as in PostgreSQL and Unix time:
to_timestamp(1789020900). A fraction keeps the milliseconds:to_timestamp(1789020900.25). Before 2026-09-25 a number meant milliseconds. - Milliseconds, like JavaScript's
Date.now(): divide by 1000.0 first, or cast:CAST(ms AS TIMESTAMP). - There is no second "format" argument. The text must look like
YYYY-MM-DD, then optionalTor space andHH:MM:SS.fff, then optionalZor+05:45. Text without a zone is UTC. - A
DATEbecomes midnight UTC of that day.
- A number means seconds, as in PostgreSQL and Unix time:
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.000Z | 2026-09-10T00:00:00.000Z | 2026-09-10T06:15:00.000Z | 2026-09-10T06:15:00.250Z | 2026-09-10T06:15:00.000Z | NULL |
(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) |
|---|---|---|---|---|
| 1 | Sita | 1788900300000 | 2026-09-08T20:45:00.000Z | 2026-09-08T20:45:00.000Z |
| 2 | Ram | 1788928200000 | 2026-09-09T04:30:00.000Z | 2026-09-09T04:30:00.000Z |
| 3 | Hari | 1789020900000 | 2026-09-10T06:15:00.000Z | 2026-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.
| Argument | Type | Meaning |
|---|---|---|
value | text, TIMESTAMP, DATE or whole number | a time, or milliseconds since 1970-01-01 UTC |
- Returns:
DATE. - NULL:
NULLin,NULLout. - Notes:
- The date is the UTC date. Nepal is 5 hours 45 minutes ahead of UTC, so between 00:00 and 05:45 Nepal time the UTC date is the day before. For the Nepal date write
to_date(time + 20700000)(20700000 ms = 5 h 45 min). to_date(86400000)works (a number of milliseconds), butCAST(86400000 AS DATE)is an error.CASTintoDATEdoes not take numbers.
- The date is the UTC date. Nepal is 5 hours 45 minutes ahead of UTC, so between 00:00 and 05:45 Nepal time the UTC date is the day before. For the Nepal date write
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-10 | 2026-09-09 | 1970-01-02 | NULL |
(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-08 | 1 |
| 2026-09-09 | 2 |
| 2026-09-10 | 1 |
(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-09 | 3 |
| 2026-09-10 | 1 |
(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:
| Type | Smallest | Biggest |
|---|---|---|
BYTE | -127 | 127 |
SHORT | -32767 | 32767 |
INT, INTEGER | -2147483647 | 2147483647 |
LONG, BIGINT | -9223372036854775807 | 9223372036854775807 |
| From | Result |
|---|---|
| a whole number | the same number, if it is in range |
DOUBLE | rounded 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 |
| text | a number like '42', ' -7' or '5.5' (spaces before are allowed, spaces after are not); a fraction is rounded |
TRUE / FALSE | 1 / 0 |
TIMESTAMP | the milliseconds since 1970-01-01, as PostgreSQL apps expect |
DATE, JSON, BYTES | error |
- Returns: the chosen integer type.
- NULL: stays
NULL. - Notes:
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) |
|---|---|---|---|---|---|
| 42 | 5 | 1 | 2 | 513 | -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) |
|---|---|---|---|---|
| 100001 | TELCO | 1000 | 1001 | 1788912000000 |
| 100002 | CITY | 10 | 11 | 1788912000000 |
| 100003 | CITY | 500 | 501 | 1788912000000 |
(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) |
|---|---|---|
| 513 | 512 | 6 |
(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.
| From | Result |
|---|---|
any number (LONG, DOUBLE, DECIMAL) | the number |
| text | a number like '512.5', '-3' or '1e3' |
BOOL, times, JSON, BYTES | error |
- Returns:
DOUBLEorFLOAT. - NULL: stays
NULL. - Notes:
- A
DOUBLEcannot hold every decimal exactly.0.1 + 0.2is shown as0.3, but the real value is0.30000000000000004(see Into STRING). For money useDECIMAL(2). FLOATloses digits:CAST(0.1 AS FLOAT)shows0.100000001490116. A value above about 3.4e38 is an error./already gives aDOUBLE(7 / 2is3.5), soCAST(7 AS DOUBLE) / 2is not needed (it is afterSET int_division = integer: integer division).
- A
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.5 | 1000 | 1.25 | 0.100000001490116 | 0.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-01 | Sales | 1250.00 | 1250 |
| 2026-09-02 | Sales | 899.99 | 899.99 |
| 2026-09-02 | Rent | 1200.50 | 1200.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.
| From | Result |
|---|---|
| a whole number | 7 becomes 7.00 |
DECIMAL | the same value with the new scale, if no digit is lost |
DOUBLE | the value rounded to scale places: 12.345 gives 12.35 for DECIMAL(2) |
| text | a number like '1250.75'; more places than scale are rounded |
BOOL, times, JSON, BYTES | error |
| Part | Meaning |
|---|---|
scale | DECIMAL(s): 0 to 18 (18 digits in all). NUMERIC(p, s): 0 to 38, p up to 38 digits |
- Returns:
DECIMAL(scale). - NULL: stays
NULL. - Notes:
- More places than
scaleare rounded to the nearest, half away from zero.CAST(round(x, 2) AS DECIMAL(2))says the same thing and is clearer to read. DECIMALwithout a scale is not exact money: it is the same asDOUBLE.- Arithmetic with
DECIMALvalues (amount * 0.13,debit - credit) is exact and gives aDECIMAL, as in PostgreSQL (DECIMAL). CAST it toDECIMAL(2)to show it with 2 places.sumandavgofDECIMALvalues areDECIMALtoo (sum). - A
DOUBLElike0.1 + 0.2is close enough to0.30, soCAST(0.1 + 0.2 AS DECIMAL(2))gives0.30. DECIMAL(s)keeps 18 digits in 64 bits: with 2 places the largest value is92233720368547758.07.NUMERIC(p, s)keeps itspdigits, up to 38:CAST(x AS NUMERIC(24,2))holds 22 digits before the point, and more is an error that names the type you wrote:cannot convert '...' to NUMERIC(24,2): numeric field overflow.
- More places than
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.00 | 1250.75 | 1500.256 | 0.30 | 1.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) |
|---|---|---|---|
| Rent | 1200.50 | 1200.50 | 1 |
| Sales | 2149.99 | 1075.00 | 2 |
(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.35 | 12.34 | 1250.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.12 | 0.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.
| From | Result |
|---|---|
| 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 |
DATE | midnight UTC of that day |
| a whole number | that many milliseconds after 1970-01-01 UTC |
DOUBLE, BOOL, JSON, BYTES | error |
- Returns:
TIMESTAMP. - NULL: stays
NULL. - Notes:
- A local time must be written with its zone offset, for example
+05:45for Nepal.'2026-09-10 11:00'is 11:00 UTC, which is 16:45 in Nepal. - Zone names (
NPT,Asia/Kathmandu) are not allowed inside the text. Only an offset like+05:45. - Other date orders (
'10/09/2026'), one-digit months ('2026-9-1') and24:00are errors. More than 3 digits after the second are cut to milliseconds. - The same as to_timestamp.
- A local time must be written with its zone offset, for example
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.000Z | 2026-09-10T11:00:00.000Z | 2026-09-10T00:00:00.000Z | 1970-01-01T00:00:00.000Z | 2026-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) |
|---|---|---|---|
| CITY | 240 | 2026-09-10T05:15:00.000Z | 2026-09-10T09:14:00.000Z |
| COAST | 236 | 2026-09-10T05:15:00.000Z | 2026-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.
| From | Result |
|---|---|
| date text | '2026-09-10' |
| time text | the UTC date of that time |
TIMESTAMP | the UTC date |
numbers, BOOL, JSON, BYTES | error (use to_date for milliseconds) |
- Returns:
DATE. - NULL: stays
NULL. - Notes:
'2026-09-10T03:00:00+05:45'is 21:15 UTC on 9 September, so itsDATEis2026-09-09.- A date that does not exist (
'2026-02-30') is an error. DATE + 1is the next day.
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-10 | 2026-09-09 | 2026-09-10 | 2026-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-09 | 8 | 3730 |
| 2026-09-10 | 24 | 4930 |
(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.
| From | Result |
|---|---|
TRUE / FALSE | the same |
the whole numbers 1 / 0 | true / false; any other number is an error |
| text | 'true', 't', '1' are true; 'false', 'f', '0' are false (any letter case) |
DOUBLE, times, JSON, BYTES | error |
- Returns:
BOOL. - NULL: stays
NULL. - Notes:
'yes','no',2and1.0are errors. Map them with CASE first.
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) |
|---|---|---|---|---|
| true | false | true | false | true |
(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) |
|---|---|
| Yes | true |
| no | false |
(2 rows)
Into STRING and SYMBOL
Syntax:
CAST(value AS STRING | VARCHAR | TEXT | SYMBOL)
Text. Every value can become text.
| From | Text |
|---|---|
| whole number | 42 |
DOUBLE | the shortest form that reads back the same: 512.5, 0.30000000000000004 |
DECIMAL(s) | with all s places: 1.50 |
BOOL | true / false |
TIMESTAMP | UTC in ISO form: 2026-09-10T05:15:00.000Z |
DATE | 2026-09-10 |
JSON | the JSON text; a JSON string keeps its quotes ("text") |
BYTES | hex with \x in front: \x4e41 |
- Returns:
STRING(orSYMBOL). - NULL: stays
NULL. An empty text''is notNULL. - Notes:
- For a time in another format or in Nepal time use to_char.
- To get the text inside a JSON string without quotes, use
->>orjson_value_text(JSON functions). ||already turns numbers into text:'CITY-' || 1.
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) |
|---|---|---|---|---|---|
| 42 | 512.5 | 1.50 | true | 2026-09-10T05:15:00.000Z | 0.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.
| From | Result |
|---|---|
| text | parsed as JSON; bad JSON is an error that says where the problem is |
numbers, DECIMAL | a JSON number: 5, 1.50 |
BOOL | true / false |
TIMESTAMP, DATE, BYTES | a JSON string with their text: "2026-09-10" |
- Returns:
JSON. - NULL: SQL
NULLstaysNULL. The text'null'becomes the JSON valuenull, which is not SQLNULL(IS NULLis false). - Notes:
- A text value must be valid JSON. The word
CITYis not JSON;'"CITY"'(with double quotes inside) is. See JSON functions for reading parts of a document. - The result tables on this page show a JSON string without its quotes, and a JSON
nullasNULL.
- A text value must be valid JSON. The word
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]} | 5 | true | "2026-09-10" | NULL | false |
(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).
| From | Result |
|---|---|
text that starts with \x | read as hex digits: '\x4e41' is the two bytes 4e and 41 |
| other text | its UTF-8 bytes: 'NA' is \x4e41; a Nepali letter is 3 bytes |
X'0A0B' | already bytes |
numbers, BOOL, times, JSON | error |
- Returns:
BYTES. - NULL: stays
NULL. - Notes:
CAST(bytes AS STRING)does not give the letters back; it gives the hex text. See bytes functions forhex,unhexand base64.
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 | \xe0a4a8e0a587e0a4aae0a4bee0a4b2 | 15 |
(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