KDB knowledge

Math functions

Round and cut numbers, take powers, roots and logarithms, divide safely, put values in buckets, and make random numbers.

These functions work on numbers: INT, LONG, DOUBLE, DECIMAL and the other number types. Sine, cosine and the normal distribution are in trigonometry and probability; money functions (interest, loans, NPV) are in finance functions.

Example: Price change of CITY, rounded to 2 decimals (sample data: sample)

SELECT time, close,
       round(close - lag(close), 2) AS change,
       round((close - lag(close)) / lag(close) * 100, 2) AS change_pct
FROM ochl_day
WHERE symbol = 'CITY'
LIMIT 5;

Result:

time (TIMESTAMP)close (DOUBLE)change (DOUBLE)change_pct (DOUBLE)
2025-12-28T00:00:00.000Z542.2NULLNULL
2025-12-29T00:00:00.000Z539.7-2.5-0.46
2025-12-30T00:00:00.000Z539.3-0.4-0.07
2025-12-31T00:00:00.000Z542.43.10.57
2026-08-23T00:00:00.000Z507.9-34.5-6.36

(5 rows)

abs

Syntax:

abs(x)

The number without its minus sign: abs(-5) is 5.

ArgumentTypeMeaning
xany numberthe value

Example

SELECT abs(-5) AS a, abs(-2.75) AS b, abs(CAST(-3.5 AS DECIMAL(2))) AS c, abs(NULL) AS d;

Result:

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

(1 row)

Example: How far the close is from the open, for each day (sample data: sample)

SELECT time, symbol, open, close, abs(close - open) AS move
FROM ochl_day
WHERE symbol = 'COAST'
ORDER BY move DESC
LIMIT 3;

Result:

time (TIMESTAMP)symbol (SYMBOL)open (DOUBLE)close (DOUBLE)move (DOUBLE)
2026-09-09T00:00:00.000ZCOAST398380.117.9
2026-09-07T00:00:00.000ZCOAST373.7379.25.5
2026-08-26T00:00:00.000ZCOAST378.13735.10000000000002

(3 rows)

round

Syntax:

round(x)
round(x, digits)

Rounds x to digits places after the decimal point. Halves go away from zero: round(2.5) is 3 and round(-2.5) is -3.

ArgumentTypeMeaning
xany numberthe value to round
digitswhole numberplaces after the point; default 0. A negative number rounds to tens, hundreds, ...

Example

SELECT round(512.456, 2) AS two_places, round(512.5) AS whole, round(-2.5) AS negative, round(1234.5, -2) AS hundreds, round(7) AS int_value, round(1.005, 2) AS half_cent;

Result:

two_places (DOUBLE)whole (DOUBLE)negative (DOUBLE)hundreds (DOUBLE)int_value (LONG)half_cent (DOUBLE)
512.46513-3120071.01

(1 row)

Example: Average close per symbol, rounded for a report (sample data: sample)

SELECT symbol, round(avg(close), 2) AS avg_close, count(*) AS days
FROM ochl_day
GROUP BY symbol
ORDER BY symbol;

Result:

symbol (SYMBOL)avg_close (DOUBLE)days (LONG)
CITY511.8119
COAST385.9319
VOLT180.9719

(3 rows)

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

SELECT round('5');

Result:

Error: line 1, column 8: round: argument 1 must be a number, got 5

round_half_even

Syntax:

round_half_even(x)
round_half_even(x, digits)

Rounds like round, but a value exactly halfway goes to the even neighbour: round_half_even(2.5) is 2, round_half_even(3.5) is 4 (banker's rounding, QuestDB's round_half_even). Adding many rounded amounts then does not drift upwards.

ArgumentTypeMeaning
xany numberthe value to round
digitswhole numberplaces after the point; default 0. A negative number rounds to tens, hundreds, ...

Example

SELECT round_half_even(2.5) AS two, round_half_even(3.5) AS four, round_half_even(-2.5) AS minus_two,
       round_half_even(2.345, 2) AS even_cent, round_half_even(2.355, 2) AS up_cent, round_half_even(1250, -2) AS hundreds;

Result:

two (DOUBLE)four (DOUBLE)minus_two (DOUBLE)even_cent (DOUBLE)up_cent (DOUBLE)hundreds (LONG)
24-22.342.361200

(1 row)

floor

Syntax:

floor(x)

Rounds down to the whole number at or below x: floor(5.7) is 5, floor(-5.2) is -6.

Example

SELECT floor(5.7) AS a, floor(-5.2) AS b, floor(9) AS c;

Result:

a (DOUBLE)b (DOUBLE)c (LONG)
5-69

(1 row)

Example: Price bands of 10 dollars (sample data: sample)

SELECT floor(close / 10) * 10 AS band, count(*) AS days
FROM ochl_day
WHERE symbol = 'CITY'
GROUP BY floor(close / 10) * 10
ORDER BY band;

Result:

band (DOUBLE)days (LONG)
4905
5007
5103
5302
5402

(5 rows)

ceil, ceiling

Syntax:

ceil(x)
ceiling(x)

Rounds up to the whole number at or above x: ceil(5.2) is 6, ceil(-5.7) is -5. ceiling is the same function.

Example

SELECT ceil(5.2) AS a, ceiling(-5.7) AS b, ceil(4) AS c;

Result:

a (DOUBLE)b (DOUBLE)c (LONG)
6-54

(1 row)

Example: How many pages for 956 rows, 100 rows per page (sample data: sample)

SELECT count(*) AS rows, ceil(count(*) / 100.0) AS pages FROM ochl_minutes;

Result:

rows (LONG)pages (DOUBLE)
95610

(1 row)

trunc, truncate

Syntax:

trunc(x)
trunc(x, digits)
truncate(x, digits)

Cuts off the digits after digits places, without rounding: trunc(512.789, 2) is 512.78, while round gives 512.79. It moves toward zero: trunc(-5.7) is -5 (but floor(-5.7) is -6). truncate is the same function.

ArgumentTypeMeaning
xany numberthe value to cut
digitswhole numberplaces after the point to keep; default 0. A negative number cuts to tens, hundreds, ...

Example

SELECT trunc(512.789, 2) AS two_places, round(512.789, 2) AS rounded, trunc(-5.7) AS negative, floor(-5.7) AS floor, truncate(1234.5, -2) AS hundreds, trunc(7) AS int_value;

Result:

two_places (DOUBLE)rounded (DOUBLE)negative (DOUBLE)floor (DOUBLE)hundreds (DOUBLE)int_value (LONG)
512.78512.79-5-612007

(1 row)

Example: Average trade rate: cut and rounded to 1 decimal (sample data: sample)

SELECT symbol, avg(rate) AS avg_rate, trunc(avg(rate), 1) AS cut, round(avg(rate), 1) AS rounded
FROM trade_log
GROUP BY symbol
ORDER BY symbol;

Result:

symbol (SYMBOL)avg_rate (DOUBLE)cut (DOUBLE)rounded (DOUBLE)
CITY515.590909090909515.5515.6
COAST399.363636363636399.3399.4
TELCO880.5880.5880.5
VOLT185185185

(4 rows)

Example: digits must be a whole number (shows an error)

SELECT trunc(5.99, 1.5);

Result:

Error: line 1, column 8: trunc: argument 2 must be a whole number, got '1.5'

sqrt

Syntax:

sqrt(x)

Square root: sqrt(16) is 4.

Example

SELECT sqrt(16) AS a, sqrt(2) AS b, sqrt(-1) AS negative;

Result:

a (DOUBLE)b (DOUBLE)negative (STRING)
41.4142135623731NULL

(1 row)

Example: Daily volatility from the variance of the close (sample data: sample)

SELECT symbol, round(sqrt(var_samp(close)), 3) AS stddev_close
FROM ochl_day
GROUP BY symbol
ORDER BY symbol;

Result:

symbol (SYMBOL)stddev_close (DOUBLE)
CITY16.198
COAST21.379
VOLT8.637

(3 rows)

cbrt

Syntax:

cbrt(x)

The cube root: the number that, multiplied by itself three times, gives x. cbrt(27) is 3, because 3 × 3 × 3 = 27. Unlike sqrt, it works for negative numbers: cbrt(-8) is -2.

ArgumentTypeMeaning
xany numberthe value

Example

SELECT cbrt(27) AS a, cbrt(-8) AS b, cbrt(2) AS c, pow(-8, 1.0 / 3) AS pow_negative;

Result:

a (DOUBLE)b (DOUBLE)c (DOUBLE)pow_negative (STRING)
3-21.25992104989487NULL

(1 row)

Example: Growth per year: 1,00,000 became 1,33,100 in 3 years

SELECT round((cbrt(133100.0 / 100000) - 1) * 100, 2) AS growth_pct_per_year;

Result:

growth_pct_per_year (DOUBLE)
10

(1 row)

pow, power

Syntax:

pow(x, y)
power(x, y)

x to the power y: pow(2, 10) is 1024. power is the same function.

ArgumentTypeMeaning
xany numberthe base
yany numberthe power; 0.5 is a square root

Example

SELECT pow(2, 10) AS a, power(2, 0.5) AS b, pow(10, -2) AS c, pow(-8, 1.0 / 3) AS not_real;

Result:

a (DOUBLE)b (DOUBLE)c (DOUBLE)not_real (STRING)
10241.41421356237310.01NULL

(1 row)

Example: Money after 5 years at 8% a year

SELECT round(100000 * pow(1 + 0.08, 5), 2) AS amount;

Result:

amount (DOUBLE)
146932.81

(1 row)

exp

Syntax:

exp(x)

The number e (2.718...) to the power x. It undoes ln.

Example

SELECT exp(0) AS a, exp(1) AS e, exp(ln(5)) AS back_to_5, exp(1000) AS too_big;

Result:

a (DOUBLE)e (DOUBLE)back_to_5 (DOUBLE)too_big (DOUBLE)
12.718281828459055NULL

(1 row)

ln, log

Syntax:

ln(x)
log(x)

ln(x) is the natural logarithm (base e). log(x) is base 10, as in PostgreSQL: log(100) is 2, the same as log10(100). log(b, x) is base b.

Example

SELECT ln(1) AS a, ln(exp(2)) AS b, log(100) AS base_10, log(2, 8) AS base_2, ln(0) AS zero;

Result:

a (DOUBLE)b (DOUBLE)base_10 (DOUBLE)base_2 (DOUBLE)zero (STRING)
0223NULL

(1 row)

Example: Log returns of CITY (sample data: sample)

SELECT time, close, round(ln(close / lag(close)), 5) AS log_return
FROM ochl_day
WHERE symbol = 'CITY'
LIMIT 4;

Result:

time (TIMESTAMP)close (DOUBLE)log_return (DOUBLE)
2025-12-28T00:00:00.000Z542.2NULL
2025-12-29T00:00:00.000Z539.7-0.00462
2025-12-30T00:00:00.000Z539.3-0.00074
2025-12-31T00:00:00.000Z542.40.00573

(4 rows)

log10

Syntax:

log10(x)

Logarithm base 10: log10(1000) is 3.

Example

SELECT log10(1000) AS a, log10(2) AS b, log10(-1) AS negative;

Result:

a (DOUBLE)b (DOUBLE)negative (STRING)
30.301029995663981NULL

(1 row)

log2

Syntax:

log2(x)

Logarithm base 2: how many times you double 1 to get x. log2(8) is 3, because 1 → 2 → 4 → 8. For a price, log2(new / old) tells how many times the price doubled.

ArgumentTypeMeaning
xany numberthe value, more than 0

Example

SELECT log2(8) AS a, log2(1024) AS b, log2(1000) AS c, log2(0) AS zero;

Result:

a (DOUBLE)b (DOUBLE)c (DOUBLE)zero (STRING)
3109.96578428466209NULL

(1 row)

Example: A share went from 100 to 800 dollars: how many doublings?

SELECT log2(800.0 / 100) AS doublings, pow(2, log2(800.0 / 100)) * 100 AS back_to_price;

Result:

doublings (DOUBLE)back_to_price (DOUBLE)
3800

(1 row)

sign

Syntax:

sign(x)

-1 for a negative number, 0 for zero, 1 for a positive number.

Example

SELECT sign(-7) AS a, sign(0) AS b, sign(3.5) AS c;

Result:

a (DOUBLE)b (DOUBLE)c (DOUBLE)
-101

(1 row)

Example: Up, down or flat days (sample data: sample)

SELECT sign(close - open) AS direction, count(*) AS days
FROM ochl_day
GROUP BY sign(close - open)
ORDER BY direction;

Result:

direction (DOUBLE)days (LONG)
-127
130

(2 rows)

mod

Syntax:

mod(x, y)
x % y

The remainder after dividing x by y: mod(10, 3) is 1. The % operator does the same.

Example

SELECT mod(10, 3) AS a, 10 % 3 AS b, mod(-10, 3) AS c, mod(10.5, 3) AS d, mod(5, NULLIF(0, 0)) AS by_zero;

Result:

a (LONG)b (LONG)c (LONG)d (DOUBLE)by_zero (STRING)
11-11.5NULL

(1 row)

Example: Every 5th transaction of the trade log (sample data: sample)

SELECT transaction_id, symbol, quantity
FROM trade_log
WHERE transaction_id % 5 = 0
ORDER BY transaction_id
LIMIT 4;

Result:

transaction_id (LONG)symbol (SYMBOL)quantity (LONG)
100005CITY500
100010CITY50
100015COAST1000
100020VOLT100

(4 rows)

greatest

Syntax:

greatest(value, value, ...)

The biggest of the values. NULL values are skipped. Works for numbers, text and times.

Example

SELECT greatest(3, 9, 4) AS a, greatest(3, NULL, 9) AS b, greatest('CITY', 'COAST') AS c, greatest(NULL, NULL) AS d;

Result:

a (LONG)b (LONG)c (STRING)d (STRING)
99COASTNULL

(1 row)

Example: The bigger of two prices (sample data: sample)

SELECT time, open, close, greatest(open, close) AS body_top
FROM ochl_day
WHERE symbol = 'VOLT'
LIMIT 3;

Result:

time (TIMESTAMP)open (DOUBLE)close (DOUBLE)body_top (DOUBLE)
2025-12-28T00:00:00.000Z187.7191.7191.7
2025-12-29T00:00:00.000Z192.9196.4196.4
2025-12-30T00:00:00.000Z195192.3195

(3 rows)

least

Syntax:

least(value, value, ...)

The smallest of the values. NULL values are skipped. Works for numbers, text and times.

Example

SELECT least(3, 9, 4) AS a, least(3, NULL, 9) AS b, least('2026-09-10', '2026-01-01') AS c;

Result:

a (LONG)b (LONG)c (STRING)
332026-01-01

(1 row)

Example: A number and a text cannot be compared (shows an error)

SELECT least(1, 'a');

Result:

Error: line 1, column 8: least: values cannot be compared

gcd

Syntax:

gcd(a, b)

The greatest common divisor: the biggest whole number that divides both a and b with no remainder. gcd(12, 18) is 6. Use it to make a ratio as small as possible, like a bonus share ratio of 20:100 that is really 1:5.

ArgumentTypeMeaning
awhole numberthe first value
bwhole numberthe second value

Example

SELECT gcd(12, 18) AS a, gcd(-12, 18) AS b, gcd(0, 5) AS c, gcd(7, 5) AS no_common;

Result:

a (LONG)b (LONG)c (LONG)no_common (LONG)
6651

(1 row)

Example: Write a bonus share ratio in its smallest form

SELECT bonus, held,
       bonus / gcd(bonus, held) AS bonus_small,
       held / gcd(bonus, held) AS held_small
FROM (SELECT 20 AS bonus, 100 AS held UNION ALL SELECT 15, 45 UNION ALL SELECT 7, 10) t;

Result:

bonus (LONG)held (LONG)bonus_small (DOUBLE)held_small (DOUBLE)
2010015
154513
710710

(3 rows)

Example: Only whole numbers (shows an error)

SELECT gcd(12.5, 5);

Result:

Error: line 1, column 8: gcd: argument 1 must be a whole number, got '12.5'

lcm

Syntax:

lcm(a, b)

The least common multiple: the smallest whole number that both a and b divide. lcm(4, 6) is 12. If one thing happens every 4 days and another every 6 days, they happen on the same day every 12 days.

ArgumentTypeMeaning
awhole numberthe first value
bwhole numberthe second value

Example

SELECT lcm(4, 6) AS a, lcm(-4, 6) AS b, lcm(0, 5) AS c, lcm(7, 5) AS d;

Result:

a (LONG)b (LONG)c (LONG)d (LONG)
1212035

(1 row)

Example: The smallest order that fits a lot size of 10 and a lot size of 25

SELECT lcm(10, 25) AS smallest_order;

Result:

smallest_order (LONG)
50

(1 row)

factorial

Syntax:

factorial(n)

n!: the product 1 × 2 × 3 × ... × n. factorial(5) is 120. It counts the ways to put n things in a row, and it is used to count combinations (how many ways to pick k things from n).

ArgumentTypeMeaning
nwhole number, 0 or morehow many things

Example

SELECT factorial(0) AS a, factorial(5) AS b, factorial(20) AS c, factorial(21) AS d, factorial(171) AS e;

Result:

a (LONG)b (LONG)c (LONG)d (DOUBLE)e (STRING)
112024329020081766400005.10909421717094e+19NULL

(1 row)

Example: How many ways to pick 3 shares from the 5 securities? (sample data: sample)

SELECT n, factorial(n) / (factorial(3) * factorial(n - 3)) AS ways_to_pick_3
FROM (SELECT count(*) AS n FROM securities) t;

Result:

n (LONG)ways_to_pick_3 (DOUBLE)
510

(1 row)

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

SELECT factorial(-1);

Result:

Error: line 1, column 8: factorial: needs 0 or more, got -1

pi

Syntax:

pi()

The number π (3.14159...): the length around a circle divided by its width. You need it with sin and cos and with radians.

Example

SELECT pi() AS pi, round(pi(), 2) AS short, 2 * pi() AS full_circle_in_radians;

Result:

pi (DOUBLE)short (DOUBLE)full_circle_in_radians (DOUBLE)
3.141592653589793.146.28318530717959

(1 row)

degrees

Syntax:

degrees(x)

Changes an angle in radians to degrees. A full circle is 360 degrees or 2π radians, so degrees(pi()) is 180. The functions asin, acos, atan and atan2 give radians; use degrees to read them.

ArgumentTypeMeaning
xany numberan angle in radians

Example

SELECT degrees(pi()) AS half_circle, degrees(pi() / 2) AS right_angle, degrees(1) AS one_radian, degrees(atan(1)) AS atan_1;

Result:

half_circle (DOUBLE)right_angle (DOUBLE)one_radian (DOUBLE)atan_1 (DOUBLE)
1809057.295779513082345

(1 row)

radians

Syntax:

radians(x)

Changes an angle in degrees to radians, the unit that sin, cos and tan need. radians(180) is π.

ArgumentTypeMeaning
xany numberan angle in degrees

Example

SELECT radians(180) AS pi, radians(90) AS right_angle, round(sin(radians(30)), 4) AS sin_30_degrees;

Result:

pi (DOUBLE)right_angle (DOUBLE)sin_30_degrees (DOUBLE)
3.141592653589791.57079632679490.5

(1 row)

width_bucket

Syntax:

width_bucket(x, low, high, count)

Cuts the range from low to high into count buckets of the same width, and says which bucket x falls in: 1 to count. A value below low is bucket 0; a value at or above high is bucket count + 1. Use it to make a histogram: a count of values per bucket.

ArgumentTypeMeaning
xany numberthe value to place
lowany numberwhere bucket 1 starts
highany numberwhere the last bucket ends (not included)
countwhole number, 1 or morehow many buckets

Example

SELECT width_bucket(512, 400, 600, 4) AS a, width_bucket(399, 400, 600, 4) AS below, width_bucket(600, 400, 600, 4) AS at_high, width_bucket(450, 600, 400, 4) AS down;

Result:

a (LONG)below (LONG)at_high (LONG)down (LONG)
3054

(1 row)

Example: Histogram of CITY's one-minute closes on 10 September (sample data: sample)

SELECT width_bucket(close, 500, 510, 5) AS bucket,
       500 + (width_bucket(close, 500, 510, 5) - 1) * 2 AS from_price,
       count(*) AS minutes
FROM ochl_minutes
WHERE symbol = 'CITY' AND time IN '2026-09-10'
GROUP BY width_bucket(close, 500, 510, 5)
ORDER BY bucket;

Result:

bucket (LONG)from_price (LONG)minutes (LONG)
150011
250287
3504109
450633

(4 rows)

Example: Daily returns in 1% buckets from -3% to +3% (sample data: sample)

SELECT width_bucket(chg, -3, 3, 6) AS bucket, count(*) AS days
FROM (SELECT pct_change(close) OVER (PARTITION BY symbol ORDER BY time) AS chg
      FROM ochl_day
      WHERE time >= '2026-08-23') t
WHERE chg IS NOT NULL
GROUP BY width_bucket(chg, -3, 3, 6)
ORDER BY bucket;

Result:

bucket (LONG)days (LONG)
11
211
311
49
55
64
71

(7 rows)

clamp

Syntax:

clamp(x, low, high)

Keeps x inside the range from low to high: below low gives low, above high gives high, else x. It is the same as least(greatest(x, low), high).

ArgumentTypeMeaning
xnumber, text or timethe value
lowsame kind as xthe smallest allowed value
highsame kind as xthe biggest allowed value

Example

SELECT clamp(15, 0, 10) AS too_big, clamp(-3, 0, 10) AS too_small, clamp(4.5, 0, 10) AS inside, clamp('m', 'a', 'k') AS text;

Result:

too_big (LONG)too_small (LONG)inside (DOUBLE)text (STRING)
1004.5k

(1 row)

Example: Circuit limit: an order price must stay within 10% of yesterday's close

Setup:

CREATE TABLE orders (id INT, symbol STRING, prev_close DOUBLE, price DOUBLE);
INSERT INTO orders VALUES (1, 'CITY', 504.9, 570.0), (2, 'COAST', 376.1, 390.0), (3, 'VOLT', 191.2, 160.0);
SELECT id, symbol, prev_close, price,
       clamp(price, round(prev_close * 0.9, 1), round(prev_close * 1.1, 1)) AS allowed_price
FROM orders
ORDER BY id;

Result:

id (INT)symbol (STRING)prev_close (DOUBLE)price (DOUBLE)allowed_price (DOUBLE)
1CITY504.9570555.4
2COAST376.1390390
3VOLT191.2160172.1

(3 rows)

Example: The lower bound must not be bigger (shows an error)

SELECT clamp(5, 10, 0);

Result:

Error: line 1, column 8: clamp: the lower bound is bigger than the upper bound

safe_divide

Syntax:

safe_divide(x, y)

x / y, but NULL when y is 0. The / operator stops the query with "division by zero" instead, as PostgreSQL does; safe_divide works like SAFE_DIVIDE in BigQuery, so copied SQL runs.

ArgumentTypeMeaning
xany numberthe number to divide
yany numberthe number to divide by

Example

SELECT safe_divide(10, 4) AS a, safe_divide(10, 0) AS by_zero, 10 / NULLIF(0, 0) AS operator, safe_divide(NULL, 2) AS null_value;

Result:

a (DOUBLE)by_zero (STRING)operator (STRING)null_value (STRING)
2.5NULLNULLNULL

(1 row)

Example: Average trade size, also on a day with no trades

Setup:

CREATE TABLE broker_day (broker INT, trades INT, shares INT);
INSERT INTO broker_day VALUES (1, 12, 3400), (34, 0, 0), (45, 5, 1250);
SELECT broker, trades, shares, safe_divide(shares, trades) AS avg_trade_size
FROM broker_day
ORDER BY broker;

Result:

broker (INT)trades (INT)shares (INT)avg_trade_size (DOUBLE)
1123400283.333333333333
3400NULL
4551250250

(3 rows)

div0

Syntax:

div0(x, y)

x / y, but 0 when y is 0 (like DIV0 in Snowflake). Use it when a zero is the right answer, for example so that a total over many rows is not hurt by a NULL.

ArgumentTypeMeaning
xany numberthe number to divide
yany numberthe number to divide by

Example

SELECT div0(10, 4) AS a, div0(10, 0) AS by_zero, div0(5, NULL) AS null_value;

Result:

a (DOUBLE)by_zero (DOUBLE)null_value (STRING)
2.50NULL

(1 row)

Example: safe_divide and div0 side by side

Setup:

CREATE TABLE broker_day (broker INT, trades INT, shares INT);
INSERT INTO broker_day VALUES (1, 12, 3400), (34, 0, 0), (45, 5, 1250);
SELECT broker, safe_divide(shares, trades) AS safe_divide, div0(shares, trades) AS div0
FROM broker_day
ORDER BY broker;

Result:

broker (INT)safe_divide (DOUBLE)div0 (DOUBLE)
1283.333333333333283.333333333333
34NULL0
45250250

(3 rows)

percent

Syntax:

percent(part, total)

part as a percent of total: part / total × 100. percent(25, 200) is 12.5.

ArgumentTypeMeaning
partany numberthe part
totalany numberthe whole

Example

SELECT percent(25, 200) AS a, percent(3, 4) AS b, percent(5, 0) AS zero_total;

Result:

a (DOUBLE)b (DOUBLE)zero_total (STRING)
12.575NULL

(1 row)

Example: Share of paying (pro) users in each city (sample data: query-app)

SELECT city, count(*) AS users,
       sum(CASE WHEN plan = 'pro' THEN 1 ELSE 0 END) AS pro_users,
       round(percent(sum(CASE WHEN plan = 'pro' THEN 1 ELSE 0 END), count(*)), 1) AS pro_pct
FROM app_users
WHERE city IS NOT NULL
GROUP BY city
ORDER BY pro_pct DESC, city;

Result:

city (STRING)users (LONG)pro_users (LONG)pro_pct (DOUBLE)
Dharan11100
Kathmandu2150
Pokhara2150
Lalitpur100

(4 rows)

is_nan, is_inf, is_finite

Syntax:

is_nan(x)
is_inf(x)
is_finite(x)

A DOUBLE can hold three special values that are not normal numbers: NaN ("not a number", for example from 0 × infinity), inf (infinity) and -inf. They can come from other programs or from a calculation that is too big. These functions test for them.

Functiontrue when x is
is_nan(x)NaN
is_inf(x)inf or -inf
is_finite(x)a normal number (not NaN, not inf)

Example

SELECT is_nan(CAST('NaN' AS DOUBLE)) AS nan, is_inf(CAST('-inf' AS DOUBLE)) AS minus_inf,
       is_finite(1e308 * 10) AS too_big_is_finite, is_finite(512.5) AS normal, is_nan(NULL) AS null_value;

Result:

nan (BOOL)minus_inf (BOOL)too_big_is_finite (BOOL)normal (BOOL)null_value (STRING)
truetruefalsetrueNULL

(1 row)

Example: Which values are normal numbers?

SELECT name, is_nan(x) AS is_nan, is_inf(x) AS is_inf, is_finite(x) AS is_finite
FROM (SELECT 'price' AS name, 512.5 AS x
      UNION ALL SELECT 'too big', 1e308 * 10
      UNION ALL SELECT 'not a number', CAST('NaN' AS DOUBLE)) t;

Result:

name (STRING)is_nan (BOOL)is_inf (BOOL)is_finite (BOOL)
pricefalsefalsetrue
too bigfalsetruefalse
not a numbertruefalsefalse

(3 rows)

random, rand

Syntax:

random()
rand()

A random number from 0 up to (but not including) 1. Every call gives a new number, also on every row. rand is the same function.

Example: Every one-minute candle gets a random number, always from 0 to 1 (sample data: sample)

SELECT count(*) AS rows, min(r) >= 0 AS at_least_0, max(r) < 1 AS below_1
FROM (SELECT random() AS r FROM ochl_minutes) t;

Result:

rows (LONG)at_least_0 (BOOL)below_1 (BOOL)
956truetrue

(1 row)

Example: Pick 3 app users for a survey (setseed makes the pick repeatable) (sample data: query-app)

SELECT setseed(0.42);
SELECT username, city FROM app_users ORDER BY random() LIMIT 3;

Result:

SELECT setseed(0.42)

setseed(0.42) (STRING)
NULL

(1 row)

SELECT username, city FROM app_users ORDER BY random() LIMIT 3

username (STRING)city (STRING)
sumanPokhara
anitaNULL
gitaDharan

(3 rows)

setseed

Syntax:

setseed(seed)

Starts the random numbers from a fixed point, the seed. After the same setseed, random() gives the same numbers again, in the same order. Use it for tests and for a random sample that you can make again.

ArgumentTypeMeaning
seednumber from -1 to 1the starting point

Example: The same seed gives the same numbers

SELECT setseed(0.5);
SELECT round(random(), 4) AS first, round(random(), 4) AS second;
SELECT setseed(0.5);
SELECT round(random(), 4) AS first_again, round(random(), 4) AS second_again;

Result:

SELECT setseed(0.5)

setseed(0.5) (STRING)
NULL

(1 row)

SELECT round(random(), 4) AS first, round(random(), 4) AS second

first (DOUBLE)second (DOUBLE)
0.13910.9194

(1 row)

SELECT setseed(0.5)

setseed(0.5) (STRING)
NULL

(1 row)

SELECT round(random(), 4) AS first_again, round(random(), 4) AS second_again

first_again (DOUBLE)second_again (DOUBLE)
0.13910.9194

(1 row)

Example: The seed must be from -1 to 1 (shows an error)

SELECT setseed(2);

Result:

Error: line 1, column 8: setseed: the seed must be between -1 and 1

Arithmetic operators

Syntax:

a + b    a - b    a * b    a / b    a % b    -a
OperatorResult
+ - *LONG when both sides are whole numbers (an INT result past INT simply becomes a LONG), else DOUBLE. A result too big for LONG is an error: "bigint out of range"
/DOUBLE: 7 / 2 is 3.5. After SET int_division = integer, whole number / whole number is a whole number, as in PostgreSQL: 7 / 2 is 3 (integer division)
%remainder, like mod
TIMESTAMP + numberthe time plus that many milliseconds
TIMESTAMP - TIMESTAMPmilliseconds between the two times
DATE + numberthe date plus that many days

Example

SELECT 2 + 3 * 4 AS a, (2 + 3) * 4 AS b, 7 / 2 AS c, 7 % 2 AS d, 5 / NULLIF(0, 0) AS e, -2 * 3 AS f, NULL + 1 AS g;

Result:

a (LONG)b (LONG)c (DOUBLE)d (LONG)e (STRING)f (LONG)g (STRING)
14203.51NULL-6NULL

(1 row)

Example: Division by zero is an error (shows an error)

SELECT 5 / 0;

Result:

Error: line 1, column 10: division by zero

Example: Too big for a LONG (shows an error)

SELECT 9223372036854775807 + 1;

Result:

Error: line 1, column 28: bigint out of range (numeric value out of range)

Example: Times: add one hour, and the minutes between two times

SELECT CAST('2026-09-10T05:15:00Z' AS TIMESTAMP) + 3600000 AS plus_one_hour,
       (CAST('2026-09-10T11:00:00Z' AS TIMESTAMP) - CAST('2026-09-10T05:15:00Z' AS TIMESTAMP)) / 60000 AS minutes;

Result:

plus_one_hour (TIMESTAMP)minutes (DOUBLE)
2026-09-10T06:15:00.000Z345

(1 row)