blob: 48d307d4fac3a737121a7b3e9b07da3c0770356b [file] [view]
---
layout: global
title: JSON_EXISTS
displayTitle: JSON_EXISTS
license: |
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
---
### Description
The `JSON_EXISTS` predicate tests whether a SQL/JSON path matches at least one item in a JSON
document, returning a `BOOLEAN`. This is the SQL-standard (SQL:2016) way to test for the presence
of a JSON value, and is commonly used to migrate queries from other systems such as Oracle, DB2,
and PostgreSQL.
Unlike `get_json_object(json_expr, path) IS NOT NULL`, `JSON_EXISTS` distinguishes a path that is
_present but whose value is JSON `null`_ (which is `true`) from a path that is _absent_ (which is
`false`).
### Syntax
```sql
JSON_EXISTS ( json_expr, path [ { TRUE | FALSE | UNKNOWN | ERROR } ON ERROR ] )
```
### Parameters
* **json_expr**
An expression that evaluates to a `STRING` containing the JSON document. A `NULL` input yields
`NULL` (SQL Unknown), regardless of the `ON ERROR` clause.
* **path**
A constant SQL/JSON path literal (for example `'$.a.b'`, `'$.tags[0]'`, or `'$.a[*].b'`). Paths
are evaluated in **lax** mode, matching Oracle and PostgreSQL: array wildcards (`[*]`) and member
wildcards (`.*` / `['*']`) are supported, and arrays are auto-wrapped/unwrapped (a member, index,
or wildcard step applied to an array is applied to each element, and a non-array value is treated
as a single-element array). A structural mismatch is a non-match, not an error. A syntactically
invalid path is rejected during analysis.
* **{ TRUE | FALSE | UNKNOWN | ERROR } ON ERROR**
Controls the result when `json_expr` is not a single well-formed JSON value (malformed input,
or a valid value followed by trailing content). `TRUE`, `FALSE`, and `UNKNOWN` produce that
value (`UNKNOWN` is a `BOOLEAN` `NULL`); `ERROR` raises an error. The default is
`FALSE ON ERROR`.
### Result
* The path matches at least one item (including a match whose value is JSON `null`) → `true`.
* The path matches nothing → `false`.
* `json_expr` is SQL `NULL` → `NULL`.
* `json_expr` is not a single well-formed JSON value → the `ON ERROR` behavior.
A structural mismatch is treated as "no match" (`false`), not an error -- for example reading an
absent key, reading a key from a scalar, an out-of-range array index, or `[*]` over an empty array.
### Examples
```sql
SELECT json_exists('{"a":{"b":1}}', '$.a.b') AS matched;
+-------+
|matched|
+-------+
| true|
+-------+
-- Present but JSON null -> true; absent -> false
SELECT json_exists('{"a":null}', '$.a') AS present_null,
json_exists('{"a":1}', '$.b') AS absent;
+------------+------+
|present_null|absent|
+------------+------+
| true| false|
+------------+------+
-- NULL input -> NULL (Unknown), regardless of the ON ERROR clause
SELECT json_exists(CAST(NULL AS STRING), '$.a' TRUE ON ERROR) AS r;
+----+
| r|
+----+
|NULL|
+----+
-- Malformed input follows the ON ERROR clause (default FALSE)
SELECT json_exists('not json', '$.a') AS default_false,
json_exists('not json', '$.a' TRUE ON ERROR) AS true_on_error,
json_exists('not json', '$.a' UNKNOWN ON ERROR) AS unknown_on_error;
+-------------+-------------+----------------+
|default_false|true_on_error|unknown_on_error|
+-------------+-------------+----------------+
| false| true| NULL|
+-------------+-------------+----------------+
-- Lax wildcards: [*] is true iff the array has elements; auto-unwrap applies a step to each element
SELECT json_exists('{"a":[1,2]}', '$.a[*]') AS has_elems,
json_exists('{"a":[]}', '$.a[*]') AS empty_array,
json_exists('{"a":[{"b":1},{"c":2}]}', '$.a[*].b') AS any_elem_has_b;
+---------+-----------+--------------+
|has_elems|empty_array|any_elem_has_b|
+---------+-----------+--------------+
| true| false| true|
+---------+-----------+--------------+
-- Use as a predicate in WHERE
SELECT id FROM docs WHERE json_exists(doc, '$.address.city');
```
### Related Statements
* [SELECT](sql-ref-syntax-qry-select.html)
* [WHERE Clause](sql-ref-syntax-qry-select-where.html)
* [JSON_TABLE](sql-ref-syntax-qry-select-json-table.html)