In-flight processing

Expression reference

Every operator, function, cast and literal you can use in row conditions and output column expressions, with examples, types and null handling.

Row conditions and output column expressions use a small, strict subset of SQL. This page lists everything the subset accepts, with examples. Anything else is refused before the pipeline starts, with the codes listed in Expression errors. Size limits are in Validation and limits.

Syntax

  • Write each expression in the source database's SQL dialect, for example T-SQL for a SQL Server source or Oracle SQL for an Oracle source.
  • An expression is one scalar value. Subqueries, SELECT clauses, aggregate and window functions are refused.
  • Refer to columns of the table by their unqualified names, such as amount, not o.amount. Names match without regard to case. Quote a name the dialect's way when it needs quoting, for example [Order Date] or "Order Date".
  • COLLATE and AT TIME ZONE are refused.

Quoted names and block comments work as in the dialect:

[Order Date] IS NOT NULL AND /* only real orders */ [Is Test] = CAST('false' AS BIT)

Literals

LiteralExamplesNotes
Number42, -7, 19.99Exact decimal, up to 38 digits with up to 38 after the point.
Text'active', 'O''Brien', N'Zürich'Single quotes. Double a quote inside the text. The N prefix is accepted.
NullNULL

The example row

The examples on this page are written in T-SQL for a SQL Server table dbo.Orders and show what each expression returns for this row:

ColumnTypeValue
order_idint1001
customer_namenvarchar(100)Ada Lovelace
emailnvarchar(255)Ada@Example.com
statusvarchar(20)shipped
notenvarchar(200)' gift ' (two spaces on each side)
quantityint12
unit_pricedecimal(10,2)9.99
discountdecimal(10,2)NULL
is_paidbit1 (true)
ordered_atdatetime21 May 2024, 13:45:00
shipped_atdatetime2NULL
embeddingvector(2)[3, 4]
centroidvector(2)[4, 3]

Operators

OperatorOperandsResultNotes
AND, ORBooleanBooleanThree-valued logic: NULL AND false is false, NULL OR true is true, otherwise NULL propagates.
NOTBooleanBooleanNOT NULL is NULL.
=, <>, <, <=, >, >=Two values of compatible typesBooleanNULL if either side is NULL.
IN (…), NOT IN (…)A value and 1 to 128 literalsBooleanThe list holds literals only. A NULL in the list makes a non-match NULL.
IS NULL, IS NOT NULLA value of any type in Types except binaryBooleanNever NULL.
+, -, *Exact numbersExact numberNever rounds. NULL if either side is NULL.
Unary -, +Exact numberExact number

Division and remainder are not supported. In T-SQL, + is numeric only: join text with CONCAT. In dialects that have the concatenation operator ||, it behaves like CONCAT. Write a range as two comparisons, for example amount >= 100 AND amount < 500.

Operator examples

ExpressionResult
is_paid OR discount > 0true (true OR NULL is true)
discount > 0 AND is_paidNULL (NULL AND true)
discount > 0 AND NOT is_paidfalse (NULL AND false is false)
status = 'Shipped'false: text compares case-sensitively
customer_name < 'B'true: text compares by UTF-16 code units
discount = 0NULL
status IN ('shipped', 'delivered')true
status NOT IN ('open', NULL)NULL: the NULL in the list makes the non-match unknown
shipped_at IS NOT NULLfalse
quantity * unit_price119.88
quantity + discountNULL
status = 42Refused: incompatible-expression-types
is_paid = 1Refused: incompatible-expression-types. Use is_paid alone.
quantity IN (1, order_id)Refused: in-literal-required

In a row condition, a NULL result means the row isn't kept.

Functions

FunctionArgumentsReturnsNotes
CASE WHEN c THEN r … [ELSE e] ENDBoolean conditions, results of a common typeThe common typeA NULL condition counts as false. Without ELSE, the result is NULL.
CASE x WHEN v THEN r … [ELSE e] ENDA value compared with = to each vThe common type
COALESCE(a, b, …)Two or more values of a common typeThe first non-null value
CAST(x AS type)See CastsThe target type
CONCAT(a, b)Exactly two text valuesTextNULL if either is NULL, unlike SQL Server's own CONCAT. Nest calls to join more.
LOWER(x), UPPER(x)TextTextUnicode case mapping, independent of collation. Not allowed on a column in row conditions.
TRIM(x)TextTextRemoves leading and trailing spaces only. TRIM(LEADING …) and TRIM(chars FROM x) are refused.
PARTIAL_MASK(x, keep_start, keep_end)Text and two whole-number literalsTextSee Masking.
HASH_MASK(x, 'alias')Text or binary, and a text literalvarchar(64)See Masking.
REDACT('text')A text literalThe literalSee Masking.
VECTOR_DISTANCE('metric', v1, v2)'cosine', 'euclidean' or 'dot', and two vector values of the same shapefloat
VECTOR_NORM(v, 'norm')A float32 vector, and 'norm1', 'norm2' or 'norminf'float
VECTOR_NORMALIZE(v, 'norm')A float32 vector, and 'norm1', 'norm2' or 'norminf'vector

Every function returns NULL when an argument it reads is NULL, except COALESCE and CASE. LOWER and UPPER on a column, PARTIAL_MASK and HASH_MASK can't be used in row conditions.

Function names are not case-sensitive. Any other function is refused. HASH and KEYED_HASH are refused too; use HASH_MASK. DISTINCT, OVER, WITHIN GROUP, named arguments and schema-qualified function names are refused.

Function examples

ExpressionResult
CASE WHEN quantity >= 100 THEN 'bulk' WHEN quantity >= 10 THEN 'case' ELSE 'unit' ENDcase
CASE status WHEN 'open' THEN 1 WHEN 'shipped' THEN 2 END2
CASE WHEN discount > 0 THEN 'discounted' ELSE 'full price' ENDfull price: the NULL condition counts as false
COALESCE(discount, 0)0.00
COALESCE(discount, 'none')Refused: incompatible-expression-types
CONCAT(CONCAT(customer_name, ' / '), status)Ada Lovelace / shipped
CONCAT(status, CAST(discount AS VARCHAR(12)))NULL
UPPER(TRIM(note))GIFT
CONCAT(customer_name, ' ', status)Refused: function-arity
UPPER(order_id)Refused: string-type
PARTIAL_MASK(email, 1, 3)A***********com
HASH_MASK(LOWER(email), 'customer')The same hash as for ada@example.com
HASH_MASK(order_id, 'customer')Refused: mask-input-type

Vector function examples

ExpressionResult
VECTOR_NORM(embedding, 'norm2')5
VECTOR_NORMALIZE(embedding, 'norm2')A vector(2) holding 0.6 and 0.8
VECTOR_DISTANCE('euclidean', embedding, centroid)About 1.414
VECTOR_DISTANCE('cosine', embedding, centroid)About 0.04
VECTOR_DISTANCE('dot', embedding, centroid)-24 (the negative dot product)

Vector functions work in a table's own output columns only: in a row condition they are refused with processing_source_predicate_unsupported, and under All tables with unsupported-function.

Casts

CAST(x AS type) accepts these target types:

Target typeDefault sizeNotes
INT, BIGINT, SMALLINT, TINYINT
DECIMAL(p, s), NUMERIC(p, s)(38, 0)p from 1 to 38, s from 0 to p.
VARCHAR(n), CHAR(n), NVARCHAR(n), NCHAR(n)1,048,576 charactersn from 1 to 1,048,576.
TEXT1,048,576 charactersTreated as nvarchar.
BITBoolean. BOOLEAN is accepted too, in dialects that have it.
DATETIME, DATETIME2Date and time without offset. TIMESTAMP is accepted too, in dialects where it names a date and time type.
DATETIMEOFFSETDate and time with offset. TIMESTAMP WITH TIME ZONE is accepted too, in dialects that have it.

TRY_CAST, CONVERT, array types, user-defined types and any other type, such as DATE, are refused.

Which conversions are allowed:

FromTo numberTo textTo BITTo date and time
NumberYesYesNoNo
TextYesYesYesYes
BITNoYesYesNo
Date and timeNoYesNoSame kind only
uniqueidentifierNoYesNoNo

Casts never round, truncate or guess. A value that doesn't convert exactly stops the pipeline when that row is processed:

ConversionRuleError
To an integer typeThe value must be whole and fit the type.integer-overflow-or-fraction, or scalar-evaluation-failed for a whole number outside the range of INT, SMALLINT or TINYINT
To DECIMAL(p, s)The value must have at most s decimal places, ignoring trailing zeros, and fit p digits. 1.2300 fits DECIMAL(18,2), 1.2345 doesn't.numeric-overflow-or-rounding, numeric-overflow
Text to numberPlain digits with an optional sign and decimal point, such as -12.50. No exponent, spaces or thousands separators.invalid-number
To text of length nThe result must fit n characters.string-overflow
Text to BITExactly true or false, in lowercase.boolean-cast
Text to DATETIME2ISO 8601 round-trip form, such as 2024-05-01T13:45:00.0000000.datetime-cast
Text to DATETIMEOFFSETISO 8601 round-trip form with an offset, such as 2024-05-01T13:45:00.0000000+02:00.datetime-offset-cast

Casting to text writes numbers in plain decimal form, BIT as true or false, dates in the same ISO 8601 round-trip form, and uniqueidentifier values as 36 lowercase characters with hyphens.

Cast examples

ExpressionResult
CAST(unit_price AS DECIMAL(18,4))9.9900
CAST(unit_price AS VARCHAR(10))'9.99'
CAST(is_paid AS VARCHAR(5))'true'
CAST(ordered_at AS VARCHAR(33))'2024-05-01T13:45:00.0000000'
CAST('2024-05-01T13:45:00.0000000' AS DATETIME2)1 May 2024, 13:45:00
CAST(NULL AS VARCHAR(10))NULL, typed varchar(10)
CAST(unit_price AS INT)Stops: integer-overflow-or-fraction, because 9.99 has a fraction
CAST(status AS INT)Stops: invalid-number, because 'shipped' isn't a number
CAST(ordered_at AS DATE)Refused: unsupported-cast

"Stops" means the expression is accepted, and the pipeline stops when it processes this row. "Refused" means the rule is refused before the start.

Types

Each column has the type family of its source column:

FamilySource types (examples)Can be used in
Exact numbertinyint, smallint, int, bigint, decimal, numeric, money, Oracle NUMBEREverything
Approximate numberfloat, realComparisons with numbers in output columns, CASE, COALESCE. No arithmetic or casts.
Textchar, varchar, nchar, nvarchar and their (max) formsEverything. Values up to 1,048,576 characters.
BooleanbitConditions, comparisons with other Boolean values, casts to text
Date and timedate, datetime, datetime2, datetimeoffset, Oracle DATE, TIMESTAMPComparisons with the same kind, and casts, in output columns only
uniqueidentifieruniqueidentifierComparisons in output columns, casts to text
Binarybinary, varbinary, Oracle RAWPass-through and HASH_MASK only

Other types, such as time or spatial types, can be kept as plain columns but can't be used in expressions (opaque-expression-type).

Two values are compatible when they are in the same family. Exact numbers mix freely, and an approximate number can be compared with an exact one. Text never converts to a number or a date by itself: quantity = '12' and ordered_at > '2024-01-01' are refused with incompatible-expression-types. Cast text explicitly where you need a date.

Text compares as binary UTF-16, whatever the column's collation: comparisons are case-sensitive and accent-sensitive, and trailing spaces count.

Row conditions accept fewer forms than output columns, because the initial load runs them on the source. See Row filtering: The initial load.

See also

Previous
Masking

If this was useful,
our newsletter will be too.

Get monthly insights on data engineering, AI, and building critical infrastructure - direct from the Spectral Core team and CEO Damir Bulic.