17.4 Types in Filter-Condition Comparisons

Comparisons in SQL/JSON path-expression filter conditions are statically typed at compile time. If the effective types of the operands of a comparison are not known to be the same then an attempt is sometimes made to reconcile them by type-casting.

A SQL/JSON path expression targets JSON data, so the operands of a comparison are JSON values. Strict type comparison of standard JSON values is straightforward: JSON data types string, number, null, object, and array are mutually exclusive and incomparable.

But values of JSON type are comparable (see Comparison and Sorting of JSON Data Type Values). And in path expressions, comparison operands are sometimes interpreted (essentially cast) as values of SQL data types. This is the case, for example, when some item methods, such as number(), are used. This section addresses the type-checking of such effective values.

You can prevent such type-casting in either of these ways:

  • Explicitly using “only” item methods. For example, applying method numberOnly() prevents implicit type-casting to a number.

  • Use the clause TYPE (STRICT) (with json_transform, json_value, json_transform, or json_exists). This has the same effect as applying the relevant "only" item methods throughout the path expression being used.

SQL is a statically typed language; types are determined at compile time. The same applies to SQL/JSON path expressions, and in particular to comparisons in filter conditions. This means that you get the same result for a query regardless of how it is evaluated — whether functionally or using features such as indexes, materialized views, and In-Memory scans.

To realize this:

  • If the types of both operands are known and they are the same then type-checking is satisfied.

  • If the types of both operands are unknown then a compile-time error is raised.

  • If the type of one operand is known and the other is unknown then the latter operand is cast to the type of the former.

    For example, in $.a?(@.b.c == 3) the type of $a.b.c is unknown at compile time. The path expression is compiled as $.a?(@.b.c.number() == 3). At runtime an attempt is thus made to cast the data that matches $a.b.c to a number. A string value "3" would be cast to the number 3, satisfying the comparison.Foot 1

  • If the types of both operands are known and they are not the same then an attempt is made to cast the type of one to the type of the other. Details are presented below.

An attempt is made to reconcile comparison operands used in the following combinations, by type-casting. You can think of a type-casting item method being implicitly applied to one of the operands in order to make it type-compatible with the other operand.

  • Number compared with double — double() is implicitly applied to the number to make it a double value.

  • Number compared with float — float() is implicitly applied to the number to make it a float value.

  • String in a supported ISO 8601 format compared with date — date() is implicitly applied to the string to make it a date value. For this, the UTC time zone (Coordinated Universal Time, zero offset) is used as the default, taking into account any time zone specified in the string.

  • String in a supported ISO 8601 format compared with timestamp without time zone — timestamp() is implicitly applied to the string to make it a timestamp value. For this, the UTC time zone (Coordinated Universal Time, zero offset) is used as the default, taking into account any time zone specified in the string.

Comparison operands used in the following combinations are not reconciled; a compile-time error is raised.

  • Number, double, or float compared with any type other than number, double, or float.

  • Boolean compared with any type other than Boolean.

  • Date or timestamp compared with string, unless the string has a supported ISO 8601 format.

  • Date compared with any non-date type other than string (in supported ISO 8601 format).

  • Timestamp (with or without time zone) compared with any non-timestamp type other than string (in supported ISO 8601 format).

  • Timestamp compared with timestamp with time zone.
  • JSON null type compared with any type other than JSON null.

Note:

When comparing values of JSON data type in SQL, the size of the values being compared, as encoded for SQL comparison, must be less than 32K bytes. Otherwise, an error is raised. In practice, this SQL encoded-for-comparison size is roughly the size of a textual representation of the same JSON data.

For example, in this query the encoded sizes of fields dept and name must each be less than 32K:

SELECT * 
  FROM emp t
  WHERE t.data.dept = 'SALES' ORDER BY t.data.name

This limit applies to SQL clauses ORDER BY and GROUP BY, as well as to the use of SQL-value comparison operators (such as > in a WHERE clause).

More precisely, the limit applies only to comparison and sorting done by SQL itself. It does not apply to comparison or sorting done within the JSON language. That is, there's no size limit for comparison or sorting done by a SQL operator for JSON, such as json_transform or json_exists. In particular, the limit doesn't apply to comparisons made in SQL/JSON path expressions.



Footnote Legend

Footnote 1: To prevent such casting here, you can explicitly apply item method numberOnly(): $.a?(@.b.c.numberOnly() == 3). Data with a string value "3" would simply not match; it would be filtered out.