Data type conversion

A cast converts a value from one data type to another. Use explicit casts when an input does not have the type required by a function or operator.

Explicit casting vs implicit casting

An explicit cast names the target type. Implicit casting, or coercion, adapts a compatible value without a written cast.

Explicit casting

Use CAST(<expr> AS <type>), <expr>::<type>, or a typed literal. Convert an order amount and event time from text, then filter by time:

VALUES
    ('o-17', '7900', '2026-06-01T10:05:00Z'),
    ('o-42', '4900', '2026-06-01T09:55:00Z')
SELECT $0 AS order_id, CAST($1 AS int) AS total_cents, $2::timestamp AS event_time
WHERE event_time >= timestamp '2026-06-01T10:00:00Z'
SELECT order_id, total_cents, event_time
+----------+-------------+----------------------+
| order_id | total_cents | event_time           |
+----------+-------------+----------------------+
| o-17     | 7900        | 2026-06-01T10:05:00Z |
+----------+-------------+----------------------+

Invalid values raise an error. Wrap the expression in TRY(...) to return NULL when conversion fails.

Implicit casting (coercion)

When matching function arguments, ScopeQL accepts these conversions without an explicit cast:

  • NULL can match any argument type. The function may still reject NULL values.
  • A non-negative int constant can match uint.
  • A uint constant within the signed integer range can match int.
  • An integer constant can match float.

These constant conversions do not apply to numeric columns. Cast an integer column explicitly when a function requires float. For example, summarize integer latency measurements as a percentile:

VALUES (95), (120), (245), (1800)
SELECT $0 AS latency_ms
AGGREGATE quantile(latency_ms::float, quantile => 0.95) AS p95_ms
+--------+
| p95_ms |
+--------+
| 1800.0 |
+--------+

Casting and precedence

The :: operator binds more tightly than arithmetic and unary minus. Use parentheses to cast a calculated value, such as the total for an order line:

VALUES (4900, 3)
SELECT $0 AS price_cents, $1 AS quantity
SELECT (price_cents * quantity)::string || ' cents' AS line_total
+-------------+
| line_total  |
+-------------+
| 14700 cents |
+-------------+

Similarly, write (-0.0)::string to convert a negative number. Writing -0.0::string tries to negate a string and fails.

Data types that can be cast

SourceTargetBehavior
int, uint, floatAnother numeric typeThe value must fit the target range. Float-to-integer casts truncate toward zero; integer-to-float casts may lose precision.
inttimestamp, intervalInterpret the integer as nanoseconds from the Unix epoch or as a duration.
timestamp, intervalintReturn the corresponding nanosecond count.
stringNumeric types, boolean, timestamp, intervalParse the text; invalid input raises an error.
Numeric types, boolean, timestamp, intervalstringFormat the value as text.
binarystringFormat bytes as uppercase hexadecimal text.
array, objectstringFormat the value as text. Use to_json when JSON serialization is required.
Any supported typeanyPreserve the value and its contained type.
anyAnother supported typeConvert the contained value if it is compatible; otherwise raise an error.
NULLAny supported typePreserve NULL.

Casting a string to any keeps it as a string; it does not parse JSON. Use parse_json to parse JSON text, then cast to array or object when a function requires that type:

SELECT length(parse_json('["sku-17","sku-42"]')::array) AS item_count
+------------+
| item_count |
+------------+
| 2          |
+------------+