Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

10.2 Logic, missing values and conversions


if

if(condition, then, else) → then when the condition is true, else else. The condition must be a boolean. Only the chosen branch is evaluated, so the other may read a missing field.

if(age >= 18, "adult", "minor")
if(qty == 0, null, price / qty)
if(true, 1, nope)          → 1          -- `nope` is never read

case

case(c1, v1, c2, v2, …, [default]) → the value of the first true condition, else default, else null. Lazy, like if.

case(qty > 5, "bulk", qty > 1, "few", "one")
case(false, 1)             → null
case(false, 1, 2)          → 2

coalesce

coalesce(a, b, …) → the first argument that is present and not null; null when none is. Missing arguments do not fail: coalesce is made for optional fields.

coalesce(nick, name)
coalesce(nope, n, 3)       → 3          -- nope missing, n null
coalesce(sales?, 0) - coalesce(costs?, 0)

exists

exists(x) → true when x is present (even null), false when missing. Never fails.

exists(nickname)
where exists(date) and date >= "2026-01-01"

optional

optional(x) → x, or null when missing. x? is the same.

optional(nick)             -- same as nick?

nullif

nullif(a, b) → null when a == b, else a. Turns a sentinel into null.

nullif(status, "")
coalesce(nullif(label, ""), code)

between

between(x, low, high) → low <= x and x <= high. x between low and high is the operator form.

between(5, 1, 10)          → true
where price between 10 and 100

bucket

bucket(x, [b0, b1, …, bn] [, default]) → the lower bound b(i) of the range [b(i), b(i+1)) holding x, else default (or null). The last bound closes the last range: with [0, 18, 65], 65 and above fall to the default. Bounds must be strictly ascending.

bucket(25, [0, 18, 65])            → 18
bucket(70, [0, 18, 65], "old")     → "old"
derive band = bucket(age, [0, 18, 30, 50, 120])

See also the bucket stage, which also counts.


to_int

to_int(x) → an integer from a number (truncated toward zero), a numeric string or a boolean (true → 1). null stays null.

to_int("42")       → 42
to_int(3.9)        → 3
to_int(-3.9)       → -3
to_int(null)       → null
to_int("x")        → error: `to_int` cannot convert String("x")

to_float

to_float(x) → a float from a number, a numeric string or a boolean; null stays null.

to_float("2.5")    → 2.5

to_string

to_string(x) → text. Numbers, booleans, arrays and objects are written as JSON; null stays null.

to_string(qty)     → "3"
to_string([1,2])   → "[1,2]"
group | by to_string(client_code) as client | … | end

to_bool

to_bool(x) → a boolean from a boolean, a number (non-zero is true), or the texts true/false, 1/0, yes/no. Anything else is an error.

to_bool("yes")     → true
to_bool(0)         → false
to_bool("maybe")   → error: `to_bool` cannot convert "maybe"

type

type(x) → the kind of a value: "null", "bool", "number", "string", "array" or "object".

type(1.5)          → "number"
type(profile)      → "object"
where type(code?) == "string"

Operators. and, or, not (and &&, ||, !) need booleans and short-circuit; in / not in test membership in an array; between … and … tests a range. See chapter 5.