PostgreSQL 中文参考文档
🌐 英文原版 官方 ↗

9.16. JSON 函数与操作符 #

9.16.1. 处理与创建 JSON 数据
9.16.2. SQL/JSON 路径语言
9.16.3. SQL/JSON 查询函数
9.16.4. JSON_TABLE

本节描述:

为了在 SQL 环境中为 JSON 数据类型提供原生支持, PostgreSQL 实现了 SQL/JSON 数据模型。 这个模型由项的序列组成。 每个项可以持有 SQL 标量值 (外加一个额外的 SQL/JSON 空值), 以及使用 JSON 数组和对象的复合数据结构。 这个模型是 JSON 规范 RFC 7159 中隐含数据模型的形式化。

SQL/JSON 允许你把 JSON 数据与常规的 SQL 数据一起处理, 并带有事务支持, 包括:

要了解更多关于 SQL/JSON 标准的信息, 请参见 [sqltr-19075-6]。 有关 PostgreSQL 支持的 JSON 类型的细节, 请参见 Section 8.14。

9.16.1. 处理与创建 JSON 数据 #

Table 9.47 展示了可用于 JSON 数据类型的操作符 (参见 Section 8.14)。 此外, Table 9.1 中展示的常规比较操作符可用于 jsonb, 但不适用于 json。 这些比较操作符遵循 Section 8.14.4 中概括的 B-tree 操作排序规则。 另请参见 Section 9.21 中的聚集函数 json_agg, 它把记录值聚集为 JSON; 以及聚集函数 json_object_agg, 它把值对聚集为一个 JSON 对象; 还有它们的 jsonb 等价函数 jsonb_agg 和 jsonb_object_agg。

Table 9.47. json 和 jsonb 操作符

操作符

说明

示例

json -> integer → json

jsonb -> integer → jsonb

提取 JSON 数组的第 n 个元素 (数组元素从零开始索引, 但负整数从末尾开始计数)。

'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> 2 → {"c":"baz"}

'[{"a":"foo"},{"b":"bar"},{"c":"baz"}]'::json -> -3 → {"a":"foo"}

json -> text → json

jsonb -> text → jsonb

用给定的键提取 JSON 对象字段。

'{"a": {"b":"foo"}}'::json -> 'a' → {"b":"foo"}

json ->> integer → text

jsonb ->> integer → text

以 text 提取 JSON 数组的第 n 个元素。

'[1,2,3]'::json ->> 2 → 3

json ->> text → text

jsonb ->> text → text

用给定的键以 text 提取 JSON 对象字段。

'{"a":1,"b":2}'::json ->> 'b' → 2

json #> text[] → json

jsonb #> text[] → jsonb

在指定的路径上提取 JSON 子对象, 路径元素可以是字段键或数组索引。

'{"a": {"b": ["foo","bar"]}}'::json #> '{a,b,1}' → "bar"

json #>> text[] → text

jsonb #>> text[] → text

以 text 在指定的路径上提取 JSON 子对象。

'{"a": {"b": ["foo","bar"]}}'::json #>> '{a,b,1}' → bar


Note

如果 JSON 输入不具备与请求相匹配的正确结构, 例如不存在这样的键或数组元素, 那么字段/元素/路径提取操作符会返回 NULL, 而不是失败。

还有一些操作符只存在于 jsonb, 如 Table 9.48 所示。 Section 8.14.4 描述了如何使用这些操作符来有效地搜索已建立索引的 jsonb 数据。

Table 9.48. 其他 jsonb 操作符

操作符

说明

示例

jsonb @> jsonb → boolean

第一个 JSON 值是否包含第二个? (关于包含关系的细节请参见 Section 8.14.3。)

'{"a":1, "b":2}'::jsonb @> '{"b":2}'::jsonb → t

jsonb <@ jsonb → boolean

第一个 JSON 值是否被包含在第二个之中?

'{"b":2}'::jsonb <@ '{"a":1, "b":2}'::jsonb → t

jsonb ? text → boolean

该文本字符串是否作为顶层键或数组元素存在于 JSON 值之中?

'{"a":1, "b":2}'::jsonb ? 'b' → t

'["a", "b", "c"]'::jsonb ? 'b' → t

jsonb ?| text[] → boolean

文本数组中的任何字符串是否作为顶层键或数组元素存在?

'{"a":1, "b":2, "c":3}'::jsonb ?| array['b', 'd'] → t

jsonb ?& text[] → boolean

文本数组中的所有字符串是否都作为顶层键或数组元素存在?

'["a", "b", "c"]'::jsonb ?& array['a', 'b'] → t

jsonb || jsonb → jsonb

连接两个 jsonb 值。 连接两个数组会产生一个包含每个输入全部元素的数组。 连接两个对象会产生一个包含它们键的并集的对象, 当存在重复的键时, 取第二个对象的值。 所有其他情形的处理方式都是把一个非数组的输入转换为一个单元素数组, 然后按两个数组的方式继续。 它不会递归地操作: 只有顶层的数组或对象结构会被合并。

'["a", "b"]'::jsonb || '["a", "d"]'::jsonb → ["a", "b", "a", "d"]

'{"a": "b"}'::jsonb || '{"c": "d"}'::jsonb → {"a": "b", "c": "d"}

'[1, 2]'::jsonb || '3'::jsonb → [1, 2, 3]

'{"a": "b"}'::jsonb || '42'::jsonb → [{"a": "b"}, 42]

要把一个数组作为单一条目追加到另一个数组, 请把它再包一层额外的数组, 例如:

'[1, 2]'::jsonb || jsonb_build_array('[3, 4]'::jsonb) → [1, 2, [3, 4]]

jsonb - text → jsonb

从一个 JSON 对象中删除一个键 (及其值), 或者从一个 JSON 数组中删除匹配的字符串值。

'{"a": "b", "c": "d"}'::jsonb - 'a' → {"c": "d"}

'["a", "b", "c", "b"]'::jsonb - 'b' → ["a", "c"]

jsonb - text[] → jsonb

从左侧操作数中删除所有匹配的键或数组元素。

'{"a": "b", "c": "d"}'::jsonb - '{a,c}'::text[] → {}

jsonb - integer → jsonb

删除具有指定索引的数组元素 (负整数从末尾开始计数)。 如果 JSON 值不是一个数组, 则抛出一个错误。

'["a", "b"]'::jsonb - 1 → ["a"]

jsonb #- text[] → jsonb

删除指定路径上的字段或数组元素, 路径元素可以是字段键或数组索引。

'["a", {"b":1}]'::jsonb #- '{1,b}' → ["a", {}]

jsonb @? jsonpath → boolean

JSON 路径是否为指定的 JSON 值返回任何项? (这只对 SQL 标准 JSON 路径表达式有用, 对 谓词检查表达式 没有用处, 因为后者总是返回一个值。)

'{"a":[1,2,3,4,5]}'::jsonb @? '$.a[*] ? (@ > 2)' → t

jsonb @@ jsonpath → boolean

返回对指定的 JSON 值执行 JSON 路径谓词检查所产生的结果。 (这只对 谓词检查表达式 有用, 对 SQL 标准 JSON 路径表达式没有用处, 因为如果路径结果不是单一的布尔值, 它会返回 NULL。)

'{"a":[1,2,3,4,5]}'::jsonb @@ '$.a[*] > 2' → t


Note

jsonpath 操作符 @? 和 @@ 会抑制以下错误: 缺失对象字段或数组元素、 非预期的 JSON 项类型、 日期时间和数字错误。 下文描述的与 jsonpath 相关的函数也可以被要求抑制这些类型的错误。 当搜索结构各异的 JSON 文档集合时, 这种行为可能有所帮助。

Table 9.49 展示了可用于构造 json 和 jsonb 值的函数。 这个表中的一些函数有一个 RETURNING 子句, 它规定要返回的数据类型。 它必须是 json、 jsonb、 bytea、 一个字符串类型 (text、 char 或 varchar), 或一个可以被转换为 json 的类型。 默认返回 json 类型。

Table 9.49. JSON 创建函数

函数

说明

示例

to_json ( anyelement ) → json

to_jsonb ( anyelement ) → jsonb

把任何 SQL 值转换为 json 或 jsonb。 数组和组合会被递归地转换为数组和对象 (多维数组在 JSON 中变成数组的数组)。 否则, 如果存在从该 SQL 数据类型到 json 的转换, 那么将使用该转换函数来执行转换;[a] 否则,会产生一个标量 JSON 值。 对于数字、布尔或空值之外的任何标量, 将使用其文本表示, 并在必要时进行转义以构成合法的 JSON 字符串值。

to_json('Fred said "Hi."'::text) → "Fred said \"Hi.\""

to_jsonb(row(42, 'Fred said "Hi."'::text)) → {"f1": 42, "f2": "Fred said \"Hi.\""}

array_to_json ( anyarray [, boolean ] ) → json

把一个 SQL 数组转换为一个 JSON 数组。 行为与 to_json 相同, 区别在于如果可选的布尔参数为真, 顶层数组元素之间会加入换行。

array_to_json('{{1,5},{99,100}}'::int[]) → [[1,5],[99,100]]

json_array ( [ { value_expression [ FORMAT JSON ] } [, ...] ] [ { NULL | ABSENT } ON NULL ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ])

json_array ( [ query_expression ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ])

用一系列 value_expression 参数, 或用 query_expression 的结果构造一个 JSON 数组, 后者必须是一条返回单列的 SELECT 查询。 如果指定了 ABSENT ON NULL, NULL 值会被忽略。 如果使用了 query_expression, 情况总是如此。

json_array(1,true,json '{"a":null}') → [1, true, {"a":null}]

json_array(SELECT * FROM (VALUES(1),(2)) t) → [1, 2]

row_to_json ( record [, boolean ] ) → json

把一个 SQL 组合值转换为一个 JSON 对象。 行为与 to_json 相同, 区别在于如果可选的布尔参数为真, 顶层元素之间会加入换行。

row_to_json(row(1,'foo')) → {"f1":1,"f2":"foo"}

json_build_array ( VARIADIC "any" ) → json

jsonb_build_array ( VARIADIC "any" ) → jsonb

用一个可变参数列表构造一个可能具有异构类型的 JSON 数组。 每个参数都按照 to_json 或 to_jsonb 被转换。

json_build_array(1, 2, 'foo', 4, 5) → [1, 2, "foo", 4, 5]

json_build_object ( VARIADIC "any" ) → json

jsonb_build_object ( VARIADIC "any" ) → jsonb

用一个可变参数列表构造一个 JSON 对象。 按照惯例, 参数列表由交替的键和值组成。 键参数被强制转换为文本; 值参数按照 to_json 或 to_jsonb 被转换。

json_build_object('foo', 1, 2, row(3,'bar')) → {"foo" : 1, "2" : {"f1":3,"f2":"bar"}}

json_object ( [ { key_expression { VALUE | ':' } value_expression [ FORMAT JSON [ ENCODING UTF8 ] ] }[, ...] ] [ { NULL | ABSENT } ON NULL ] [ { WITH | WITHOUT } UNIQUE [ KEYS ] ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ])

用给出的所有键/值对构造一个 JSON 对象, 如果没有给出任何键/值对, 则构造一个空对象。 key_expression 是一个定义 JSON 键的标量表达式, 它会被转换为 text 类型。 它不能为 NULL, 也不能属于一个具有到 json 类型转换的类型。 如果指定了 WITH UNIQUE KEYS, 那么不得存在任何重复的 key_expression。 如果指定了 ABSENT ON NULL, 那么任何 value_expression 求值为 NULL 的对都会从输出中被省略; 如果指定了 NULL ON NULL 或省略了该子句, 则该键会被包括进来, 其值为 NULL。

json_object('code' VALUE 'P123', 'title': 'Jaws') → {"code" : "P123", "title" : "Jaws"}

json_object ( text[] ) → json

jsonb_object ( text[] ) → jsonb

用一个文本数组构造一个 JSON 对象。 该数组必须恰好有一个维度且成员数量为偶数, 在那种情况下它们被当作交替的键/值对; 或者有两个维度, 使得每个内部数组恰好有两个元素, 它们被当作一个键/值对。 所有的值都会被转换为 JSON 字符串。

json_object('{a, 1, b, "def", c, 3.5}') → {"a" : "1", "b" : "def", "c" : "3.5"}

json_object('{{a, 1}, {b, "def"}, {c, 3.5}}') → {"a" : "1", "b" : "def", "c" : "3.5"}

json_object ( keys text[], values text[] ) → json

jsonb_object ( keys text[], values text[] ) → jsonb

这种形式的 json_object 从单独的文本数组中成对地取得键和值。 否则它与单参数形式完全相同。

json_object('{a,b}', '{1,2}') → {"a": "1", "b": "2"}

json ( expression [ FORMAT JSON [ ENCODING UTF8 ]] [ { WITH | WITHOUT } UNIQUE [ KEYS ]] ) → json

把一个指定为 text 或 bytea 字符串 (UTF8 编码) 的给定表达式转换为 JSON 值。 如果 expression 为 NULL, 则返回一个 SQL 空值。 如果指定了 WITH UNIQUE, 那么 expression 不得包含任何重复的对象键。

json('{"a":123, "b":[true,"foo"], "a":"bar"}') → {"a":123, "b":[true,"foo"], "a":"bar"}

json_scalar ( expression )

把一个给定的 SQL 标量值转换为一个 JSON 标量值。 如果输入为 NULL, 则返回一个 SQL 空。 如果输入是数字或布尔值, 则返回相应的 JSON 数字或布尔值。 对于任何其他值, 则返回一个 JSON 字符串。

json_scalar(123.45) → 123.45

json_scalar(CURRENT_TIMESTAMP) → "2022-05-10T10:51:04.62128-04:00"

json_serialize ( expression [ FORMAT JSON [ ENCODING UTF8 ] ] [ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ] )

把一个 SQL/JSON 表达式转换为字符或二进制字符串。 expression 可以是任何 JSON 类型、 任何字符串类型, 或 UTF8 编码的 bytea。 在 RETURNING 中使用的返回类型可以是任何字符串类型或 bytea。 默认为 text。

json_serialize('{ "a" : 1 } ' RETURNING bytea) → \x7b20226122203a2031207d20

[a] 例如, hstore 扩展有一个从 hstore 到 json 的转换, 因此通过 JSON 创建函数转换的 hstore 值会被表示为 JSON 对象, 而非原始的字符串值。


Table 9.50 详述了用于测试 JSON 的 SQL/JSON 设施。

Table 9.50. SQL/JSON 测试函数

函数签名

说明

示例

expression IS [ NOT ] JSON [ { VALUE | SCALAR | ARRAY | OBJECT } ] [ { WITH | WITHOUT } UNIQUE [ KEYS ] ]

这个谓词测试 expression 是否可以被解析为 JSON, 可能是某种指定类型的 JSON。 如果指定了 SCALAR 或 ARRAY 或 OBJECT, 那么测试的就是 JSON 是否属于那种特定的类型。 如果指定了 WITH UNIQUE KEYS, 那么 expression 中的任何对象也都会被测试是否拥有重复的键。

SELECT js,
  js IS JSON "json?",
  js IS JSON SCALAR "scalar?",
  js IS JSON OBJECT "object?",
  js IS JSON ARRAY "array?"
FROM (VALUES
      ('123'), ('"abc"'), ('{"a": "b"}'), ('[1,2]'),('abc')) foo(js);
     js     | json? | scalar? | object? | array?
------------+-------+---------+---------+--------
 123        | t     | t       | f       | f
 "abc"      | t     | t       | f       | f
 {"a": "b"} | t     | f       | t       | f
 [1,2]      | t     | f       | f       | t
 abc        | f     | f       | f       | f

SELECT js,
  js IS JSON OBJECT "object?",
  js IS JSON ARRAY "array?",
  js IS JSON ARRAY WITH UNIQUE KEYS "array w. UK?",
  js IS JSON ARRAY WITHOUT UNIQUE KEYS "array w/o UK?"
FROM (VALUES ('[{"a":"1"},
 {"b":"2","b":"3"}]')) foo(js);
-[ RECORD 1 ]-+--------------------
js            | [{"a":"1"},        +
              |  {"b":"2","b":"3"}]
object?       | f
array?        | t
array w. UK?  | f
array w/o UK? | t


Table 9.51 展示了可用于处理 json 和 jsonb 值的函数。

Table 9.51. JSON 处理函数

函数

说明

示例

json_array_elements ( json ) → setof json

jsonb_array_elements ( jsonb ) → setof jsonb

把顶层的 JSON 数组展开为一组 JSON 值。

select * from json_array_elements('[1,true, [2,false]]') →

   value
-----------
 1
 true
 [2,false]

json_array_elements_text ( json ) → setof text

jsonb_array_elements_text ( jsonb ) → setof text

把顶层的 JSON 数组展开为一组 text 值。

select * from json_array_elements_text('["foo", "bar"]') →

   value
-----------
 foo
 bar

json_array_length ( json ) → integer

jsonb_array_length ( jsonb ) → integer

返回顶层 JSON 数组中的元素数量。

json_array_length('[1,2,3,{"f1":1,"f2":[5,6]},4]') → 5

jsonb_array_length('[]') → 0

json_each ( json ) → setof record ( key text, value json )

jsonb_each ( jsonb ) → setof record ( key text, value jsonb )

把顶层的 JSON 对象展开为一组键/值对。

select * from json_each('{"a":"foo", "b":"bar"}') →

 key | value
-----+-------
 a   | "foo"
 b   | "bar"

json_each_text ( json ) → setof record ( key text, value text )

jsonb_each_text ( jsonb ) → setof record ( key text, value text )

把顶层的 JSON 对象展开为一组键/值对。 返回的 value 将属于 text 类型。

select * from json_each_text('{"a":"foo", "b":"bar"}') →

 key | value
-----+-------
 a   | foo
 b   | bar

json_extract_path ( from_json json, VARIADIC path_elems text[] ) → json

jsonb_extract_path ( from_json jsonb, VARIADIC path_elems text[] ) → jsonb

在指定的路径上提取 JSON 子对象。 (这在功能上等同于 #> 操作符, 但在某些情况下把路径写成一个可变参数列表会更方便。)

json_extract_path('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → "foo"

json_extract_path_text ( from_json json, VARIADIC path_elems text[] ) → text

jsonb_extract_path_text ( from_json jsonb, VARIADIC path_elems text[] ) → text

在指定的路径上以 text 提取 JSON 子对象。 (这在功能上等同于 #>> 操作符。)

json_extract_path_text('{"f2":{"f3":1},"f4":{"f5":99,"f6":"foo"}}', 'f4', 'f6') → foo

json_object_keys ( json ) → setof text

jsonb_object_keys ( jsonb ) → setof text

返回顶层 JSON 对象中键的集合。

select * from json_object_keys('{"f1":"abc","f2":{"f3":"a", "f4":"b"}}') →

 json_object_keys
------------------
 f1
 f2

json_populate_record ( base anyelement, from_json json ) → anyelement

jsonb_populate_record ( base anyelement, from_json jsonb ) → anyelement

把顶层的 JSON 对象展开为一行, 该行具有 base 参数的组合类型。 会在 JSON 对象中扫描名字与输出行类型的列名相匹配的字段, 并把它们的值插入到输出的那些列中。 (与任何输出列名都不对应的字段会被忽略。) 在典型用法中, base 的值就是 NULL, 这意味着任何不匹配任何对象字段的输出列都会被填充为空。 然而, 如果 base 不是 NULL, 那么它所包含的值会被用于未匹配的列。

要把一个 JSON 值转换为一个输出列的 SQL 类型, 会依次应用以下规则:

  • 一个 JSON 空值在所有情况下都会被转换为一个 SQL 空。

  • 如果输出列是 json 或 jsonb 类型, 那么该 JSON 值会被精确地原样重现。

  • 如果输出列是一个组合 (行) 类型, 并且该 JSON 值是一个 JSON 对象, 那么该对象的字段会通过递归应用这些规则被转换为输出行类型的列。

  • 类似地, 如果输出列是一个数组类型, 并且该 JSON 值是一个 JSON 数组, 那么该 JSON 数组的元素会通过递归应用这些规则被转换为输出数组的元素。

  • 否则, 如果该 JSON 值是一个字符串, 那么字符串的内容会被交给该列数据类型的输入转换函数。

  • 否则, 该 JSON 值的普通文本表示会被交给该列数据类型的输入转换函数。

虽然下面的例子使用的是一个常量 JSON 值, 但典型的用法是在查询的 FROM 子句中从另一张表横向引用一个 json 或 jsonb 列。 在 FROM 子句中写 json_populate_record 是一种好做法, 因为所有被提取的列都可以被使用, 而无需重复的函数调用。

create type subrowtype as (d int, e text); create type myrowtype as (a int, b text[], c subrowtype);

select * from json_populate_record(null::myrowtype, '{"a": 1, "b": ["2", "a b"], "c": {"d": 4, "e": "a b c"}, "x": "foo"}') →

 a |   b       |      c
---+-----------+-------------
 1 | {2,"a b"} | (4,"a b c")

jsonb_populate_record_valid ( base anyelement, from_json json ) → boolean

用于测试 jsonb_populate_record 的函数。 如果对于给定的输入 JSON 对象, 一次 jsonb_populate_record 输入会不出错地完成 (也就是说, 它是有效的输入), 则返回 true; 否则返回 false。

create type jsb_char2 as (a char(2));

select jsonb_populate_record_valid(NULL::jsb_char2, '{"a": "aaa"}'); →

 jsonb_populate_record_valid
-----------------------------
 f
(1 row)

select * from jsonb_populate_record(NULL::jsb_char2, '{"a": "aaa"}') q; →

ERROR:  value too long for type character(2)

select jsonb_populate_record_valid(NULL::jsb_char2, '{"a": "aa"}'); →

 jsonb_populate_record_valid
-----------------------------
 t
(1 row)

select * from jsonb_populate_record(NULL::jsb_char2, '{"a": "aa"}') q; →

 a
----
 aa
(1 row)

json_populate_recordset ( base anyelement, from_json json ) → setof anyelement

jsonb_populate_recordset ( base anyelement, from_json jsonb ) → setof anyelement

把顶层的由对象组成的 JSON 数组展开为一组行, 每行具有 base 参数的组合类型。 该 JSON 数组的每个元素都会按照上文针对 json[b]_populate_record 描述的方式被处理。

create type twoints as (a int, b int);

select * from json_populate_recordset(null::twoints, '[{"a":1,"b":2}, {"a":3,"b":4}]') →

 a | b
---+---
 1 | 2
 3 | 4

json_to_record ( json ) → record

jsonb_to_record ( jsonb ) → record

把顶层的 JSON 对象展开为一行, 该行具有由一个 AS 子句定义的组合类型。 (与所有返回 record 的函数一样, 调用查询必须用一个 AS 子句显式地定义该记录的结构。) 输出记录由该 JSON 对象的字段填充, 方式与上文针对 json[b]_populate_record 描述的相同。 由于没有输入记录值, 未匹配的列总是被填充为空。

create type myrowtype as (a int, b text);

select * from json_to_record('{"a":1,"b":[1,2,3],"c":[1,2,3],"e":"bar","r": {"a": 123, "b": "a b c"}}') as x(a int, b text, c int[], d text, r myrowtype) →

 a |    b    |    c    | d |       r
---+---------+---------+---+---------------
 1 | [1,2,3] | {1,2,3} |   | (123,"a b c")

json_to_recordset ( json ) → setof record

jsonb_to_recordset ( jsonb ) → setof record

把顶层的由对象组成的 JSON 数组展开为一组行, 每行具有由一个 AS 子句定义的组合类型。 (与所有返回 record 的函数一样, 调用查询必须用一个 AS 子句显式地定义该记录的结构。) 该 JSON 数组的每个元素都会按照上文针对 json[b]_populate_record 描述的方式被处理。

select * from json_to_recordset('[{"a":1,"b":"foo"}, {"a":"2","c":"bar"}]') as x(a int, b text) →

 a |  b
---+-----
 1 | foo
 2 |

jsonb_set ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean ] ) → jsonb

返回 target, 其中由 path 指定的项被替换为 new_value; 或者如果 create_if_missing 为真 (这是默认值) 且由 path 指定的项不存在, 则加入 new_value。 路径中所有更早的步骤都必须存在, 否则会原样返回 target。 与面向路径的操作符一样, path 中出现的负整数从 JSON 数组的末尾开始计数。 如果最后的路径步骤是一个越界的数组索引, 并且 create_if_missing 为真, 那么当索引为负时, 新值会被加在数组的开头, 为正时加在末尾。

jsonb_set('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', '[2,3,4]', false) → [{"f1": [2, 3, 4], "f2": null}, 2, null, 3]

jsonb_set('[{"f1":1,"f2":null},2]', '{0,f3}', '[2,3,4]') → [{"f1": 1, "f2": null, "f3": [2, 3, 4]}, 2]

jsonb_set_lax ( target jsonb, path text[], new_value jsonb [, create_if_missing boolean [, null_value_treatment text ]] ) → jsonb

如果 new_value 不是 NULL, 其行为与 jsonb_set 完全相同。 否则按照 null_value_treatment 的值行事, 它必须是 'raise_exception'、 'use_json_null'、 'delete_key' 或 'return_target' 之一。 默认值为 'use_json_null'。

jsonb_set_lax('[{"f1":1,"f2":null},2,null,3]', '{0,f1}', null) → [{"f1": null, "f2": null}, 2, null, 3]

jsonb_set_lax('[{"f1":99,"f2":null},2]', '{0,f3}', null, true, 'return_target') → [{"f1": 99, "f2": null}, 2]

jsonb_insert ( target jsonb, path text[], new_value jsonb [, insert_after boolean ] ) → jsonb

返回插入了 new_value 的 target。 如果由 path 指定的项是一个数组元素, 那么当 insert_after 为假 (这是默认值) 时, new_value 会被插在该项之前, 为真时插在其后。 如果由 path 指定的项是一个对象字段, 那么只有当该对象尚未包含那个键时, 才会插入 new_value。 路径中所有更早的步骤都必须存在, 否则会原样返回 target。 与面向路径的操作符一样, path 中出现的负整数从 JSON 数组的末尾开始计数。 如果最后的路径步骤是一个越界的数组索引, 那么当索引为负时新值会被加在数组的开头, 为正时加在数组的末尾。

jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"') → {"a": [0, "new_value", 1, 2]}

jsonb_insert('{"a": [0,1,2]}', '{a, 1}', '"new_value"', true) → {"a": [0, 1, "new_value", 2]}

json_strip_nulls ( target json [,strip_in_arrays boolean ] ) → json

jsonb_strip_nulls ( target jsonb [,strip_in_arrays boolean ] ) → jsonb

递归地从给定的 JSON 值中删除所有具有空值的对象字段。 如果 strip_in_arrays 为真 (默认为假), 空的数组元素也会被去除。 否则它们不会被去除。 单纯的空值永远不会被去除。

json_strip_nulls('[{"f1":1, "f2":null}, 2, null, 3]') → [{"f1":1},2,null,3]

jsonb_strip_nulls('[1,2,null,3,4]', true) → [1,2,3,4]

jsonb_path_exists ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

检查 JSON 路径是否为指定的 JSON 值返回任何项。 (这只对 SQL 标准 JSON 路径表达式有用, 对 谓词检查表达式 没有用处, 因为后者总是返回一个值。) 如果指定了 vars 参数, 它必须是一个 JSON 对象, 并且它的字段提供要被替换进 jsonpath 表达式的命名值。 如果指定了 silent 参数并且它为 true, 该函数会抑制与 @? 和 @@ 操作符所抑制的相同的错误。

jsonb_path_exists('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → t

jsonb_path_match ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

返回对指定的 JSON 值执行 JSON 路径谓词检查所产生的 SQL 布尔结果。 (这只对 谓词检查表达式 有用, 对 SQL 标准 JSON 路径表达式没有用处, 因为如果路径结果不是单一的布尔值, 它会失败或返回 NULL。) 可选的 vars 和 silent 参数的行为与 jsonb_path_exists 中的相同。

jsonb_path_match('{"a":[1,2,3,4,5]}', 'exists($.a[*] ? (@ >= $min && @ <= $max))', '{"min":2, "max":4}') → t

jsonb_path_query ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb

返回 JSON 路径为指定的 JSON 值返回的所有 JSON 项。 对于 SQL 标准 JSON 路径表达式, 它返回从 target 中选出的 JSON 值。 对于 谓词检查表达式, 它返回谓词检查的结果: true、 false 或 null。 可选的 vars 和 silent 参数的行为与 jsonb_path_exists 中的相同。

select * from jsonb_path_query('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') →

 jsonb_path_query
------------------
 2
 3
 4

jsonb_path_query_array ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

以一个 JSON 数组的形式返回 JSON 路径为指定的 JSON 值返回的所有 JSON 项。 参数与 jsonb_path_query 的相同。

jsonb_path_query_array('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → [2, 3, 4]

jsonb_path_query_first ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

返回 JSON 路径为指定的 JSON 值返回的第一个 JSON 项, 如果没有结果则返回 NULL。 参数与 jsonb_path_query 的相同。

jsonb_path_query_first('{"a":[1,2,3,4,5]}', '$.a[*] ? (@ >= $min && @ <= $max)', '{"min":2, "max":4}') → 2

jsonb_path_exists_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

jsonb_path_match_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → boolean

jsonb_path_query_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → setof jsonb

jsonb_path_query_array_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

jsonb_path_query_first_tz ( target jsonb, path jsonpath [, vars jsonb [, silent boolean ]] ) → jsonb

这些函数的行为类似于上文描述的、不带 _tz 后缀的对应函数, 只是这些函数支持需要进行时区感知转换的日期/时间值比较。 下面的例子要求把仅含日期的值 2015-08-02 解释为一个带时区的时间戳, 因此结果取决于当前的 TimeZone 设置。 由于这种依赖关系, 这些函数被标记为稳定的, 这意味着它们不能被用在索引中。 它们的对应函数是不可变的, 因此可以用于索引; 但如果被要求做这样的比较, 它们会抛出错误。

jsonb_path_exists_tz('["2015-08-01 12:00:00-05"]', '$[*] ? (@.datetime() < "2015-08-02".datetime())') → t

jsonb_pretty ( jsonb ) → text

把给定的 JSON 值转换为美化打印的、 带缩进的文本。

jsonb_pretty('[{"f1":1,"f2":null}, 2]') →

[
    {
        "f1": 1,
        "f2": null
    },
    2
]

json_typeof ( json ) → text

jsonb_typeof ( jsonb ) → text

以文本字符串的形式返回顶层 JSON 值的类型。 可能的类型是 object、 array、 string、 number、 boolean 和 null。 (null 结果不应当与 SQL NULL 混淆; 请参见例子。)

json_typeof('-123.4') → number

json_typeof('null'::json) → null

json_typeof(NULL::json) IS NULL → t


9.16.2. SQL/JSON 路径语言 #

SQL/JSON 路径表达式规定要从 JSON 值中检索的项, 类似于用于访问 XML 内容的 XPath 表达式。 在 PostgreSQL 中, 路径表达式被实现为 jsonpath 数据类型, 并且可以使用 Section 8.14.7 中描述的任何元素。

JSON 查询函数和操作符把提供的路径表达式传递给 路径引擎进行求值。 如果该表达式与被查询的 JSON 数据相匹配, 则返回相应的 JSON 项或项的集合。 如果没有匹配, 结果将是 NULL、 false 或一个错误, 取决于函数。 路径表达式以 SQL/JSON 路径语言书写, 并且可以包括算术表达式和函数。

一个路径表达式由 jsonpath 数据类型所允许的元素序列组成。 路径表达式通常从左到右求值, 但你可以使用圆括号来改变运算的顺序。 如果求值成功, 会产生一个 JSON 项的序列, 并且求值结果会被返回给完成指定计算的 JSON 查询函数。

要引用被查询的 JSON 值 (即 上下文项), 请在路径表达式中使用 $ 变量。 路径的第一个元素必须始终是 $。 它后面可以跟一个或多个 访问器操作符, 这些操作符会逐层深入 JSON 结构, 检索上下文项的子项。 每个访问器操作符作用于前一次求值步骤的结果, 并从每个输入项产生零个、一个或多个输出项。

例如, 假设你有一些来自 GPS 追踪器的 JSON 数据想要解析, 例如:

SELECT '{
  "track": {
    "segments": [
      {
        "location":   [ 47.763, 13.4034 ],
        "start time": "2018-10-14 10:05:14",
        "HR": 73
      },
      {
        "location":   [ 47.706, 13.2635 ],
        "start time": "2018-10-14 10:39:21",
        "HR": 135
      }
    ]
  }
}' AS json \gset

(上面的例子可以被复制并粘贴到 psql 中, 为后面的例子做好准备。 然后 psql 会把 :'json' 展开为一个包含该 JSON 值的、带有适当引号的字符串常量。)

要检索可用的追踪段, 你需要使用 .key 访问器操作符穿过外围的 JSON 对象逐层下降, 例如:

=> select jsonb_path_query(:'json', '$.track.segments');
                                                                         jsonb_path_query
-----------------------------------------------------------​-----------------------------------------------------------​---------------------------------------------
 [{"HR": 73, "location": [47.763, 13.4034], "start time": "2018-10-14 10:05:14"}, {"HR": 135, "location": [47.706, 13.2635], "start time": "2018-10-14 10:39:21"}]

要检索一个数组的内容, 你通常使用 [*] 操作符。 下面的例子会返回所有可用追踪段的位置坐标:

=> select jsonb_path_query(:'json', '$.track.segments[*].location');
 jsonb_path_query
-------------------
 [47.763, 13.4034]
 [47.706, 13.2635]

这里我们从完整的 JSON 输入值 ($) 开始, 然后 .track 访问器选中与 "track" 对象键关联的 JSON 对象, 接着 .segments 访问器选中那个对象内与 "segments" 键关联的 JSON 数组, 然后 [*] 访问器选中该数组的每个元素 (产生一系列项), 接着 .location 访问器选中每个这样的对象内与 "location" 键关联的 JSON 数组。 在这个例子中, 每个对象都有 "location" 键; 但如果其中任何一个没有, .location 访问器对该输入项就只会简单地不产生任何输出。

要只返回第一段的坐标, 你可以在 [] 访问器操作符中指定相应的下标。 回顾一下, JSON 数组索引是从 0 开始的:

=> select jsonb_path_query(:'json', '$.track.segments[0].location');
 jsonb_path_query
-------------------
 [47.763, 13.4034]

每次路径求值步骤的结果都可以由 Section 9.16.2.3 中列出的一个或多个 jsonpath 操作符和方法处理。 每个方法名之前必须有一个点。 例如, 你可以获得一个数组的尺寸:

=> select jsonb_path_query(:'json', '$.track.segments.size()');
 jsonb_path_query
------------------
 2

在路径表达式中使用 jsonpath 操作符和方法的更多例子, 将在下文的 Section 9.16.2.3 中给出。

路径中还可以包含 过滤表达式, 它们的运作方式类似于 SQL 中的 WHERE 子句。 过滤表达式以一个问号开始, 并在圆括号中提供一个条件:

? (condition)

过滤表达式必须写在它们应当应用的那个路径求值步骤之后。 那一步的结果会被过滤, 只包含满足所提供条件的项。 SQL/JSON 定义了三值逻辑, 因此条件可以产生 true、 false 或 unknown。 unknown 值扮演的角色与 SQL 的 NULL 相同, 并且可以用 is unknown 谓词来测试它。 进一步的路径求值步骤只会使用过滤表达式为其返回了 true 的那些项。

可以在过滤表达式中使用的函数和操作符列在 Table 9.53 中。 在过滤表达式内, @ 变量表示正在被考虑的值 (即前一个路径步骤的一个结果)。 你可以在 @ 之后书写访问器操作符来检索分量项。

例如, 假设你想检索所有高于 130 的心率值。 你可以这样实现:

=> select jsonb_path_query(:'json', '$.track.segments[*].HR ? (@ > 130)');
 jsonb_path_query
------------------
 135

要得到具有这样的值的段的开始时间, 你必须在选择开始时间之前先过滤掉不相关的段, 因此过滤表达式被应用在前一步上, 并且条件中使用的路径有所不同:

=> select jsonb_path_query(:'json', '$.track.segments[*] ? (@.HR > 130)."start time"');
   jsonb_path_query
-----------------------
 "2018-10-14 10:39:21"

如果需要, 你可以按顺序使用多个过滤表达式。 下面的例子选择所有包含坐标相关且心率值高的位置的段的开始时间:

=> select jsonb_path_query(:'json', '$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"');
   jsonb_path_query
-----------------------
 "2018-10-14 10:39:21"

在不同的嵌套层级上使用过滤表达式也是允许的。 下面的例子先按位置过滤所有段, 然后为这些段返回高心率值 (如果有的话):

=> select jsonb_path_query(:'json', '$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)');
 jsonb_path_query
------------------
 135

你还可以把过滤表达式彼此嵌套。 这个例子在轨迹包含任何高心率值的段时返回该轨迹的尺寸, 否则返回一个空序列:

=> select jsonb_path_query(:'json', '$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()');
 jsonb_path_query
------------------
 2

9.16.2.1. 与 SQL 标准的差异 #

PostgreSQL 对 SQL/JSON 路径语言的实现与 SQL/JSON 标准有以下偏离。

9.16.2.1.1. 布尔谓词检查表达式 #

作为对 SQL 标准的扩展, PostgreSQL 的路径表达式可以是一个布尔谓词, 而 SQL 标准只允许在过滤器内使用谓词。 SQL 标准的路径表达式返回被查询 JSON 值的相关元素, 而谓词检查表达式返回该谓词的单一三值 jsonb 结果: true、 false 或 null。 例如, 我们可以写这条符合 SQL 标准的过滤表达式:

=> select jsonb_path_query(:'json', '$.track.segments ?(@[*].HR > 130)');
                                jsonb_path_query
-----------------------------------------------------------​----------------------
 {"HR": 135, "location": [47.706, 13.2635], "start time": "2018-10-14 10:39:21"}

类似的谓词检查表达式则简单地返回 true, 表示存在一个匹配:

=> select jsonb_path_query(:'json', '$.track.segments[*].HR > 130');
 jsonb_path_query
------------------
 true

Note

在 @@ 操作符 (以及 jsonb_path_match 函数) 中要求使用谓词检查表达式, 而不应当把它们与 @? 操作符 (或 jsonb_path_exists 函数) 一起使用。

9.16.2.1.2. 正则表达式解释 #

在 like_regex 过滤器中使用的正则表达式模式的解释存在微小的差异, 如 Section 9.16.2.4 中所描述。

9.16.2.2. 严格模式与宽松模式 #

当你查询 JSON 数据时, 路径表达式可能与实际的 JSON 数据结构不匹配。 访问对象的一个不存在的成员或数组的一个元素的尝试被定义为 结构错误。 SQL/JSON 路径表达式有两种处理结构错误的模式:

  • 宽松模式 (默认) — 路径引擎隐式地把被查询的数据适配到指定的路径。 任何无法按下文所述方式修复的结构错误都会被抑制, 产生空匹配。

  • 严格模式 — 如果发生结构错误, 会抛出一个错误。

宽松模式便于在 JSON 数据不符合预期模式时让 JSON 文档与路径表达式相匹配。 如果一个操作数不满足某个特定操作的要求, 它可以被自动包装为 SQL/JSON 数组, 或者通过把它的元素转换为 SQL/JSON 序列来解包, 然后再执行该操作。 此外, 比较操作符在宽松模式下会自动解包它们的操作数, 因此你可以开箱即用地比较 SQL/JSON 数组。 一个尺寸为 1 的数组被视为与其唯一元素相等。 在以下情况下不执行自动解包:

  • 路径表达式包含 type() 或 size() 方法, 它们分别返回数组的类型和元素的数量。

  • 被查询的 JSON 数据包含嵌套数组。 在这种情况下, 只有最外层的数组被解包, 而所有内部的数组保持不变。 因此, 隐式解包在每个路径求值步骤内只能向下进行一层。

例如, 在查询上面列出的 GPS 数据时, 使用宽松模式时你可以不必在意它存储的是一个段的数组:

=> select jsonb_path_query(:'json', 'lax $.track.segments.location');
 jsonb_path_query
-------------------
 [47.763, 13.4034]
 [47.706, 13.2635]

在严格模式下, 指定的路径必须与被查询 JSON 文档的结构精确匹配, 因此使用这个路径表达式会导致错误:

=> select jsonb_path_query(:'json', 'strict $.track.segments.location');
ERROR:  jsonpath member accessor can only be applied to an object

要得到与宽松模式下相同的结果, 你必须显式地解包 segments 数组:

=> select jsonb_path_query(:'json', 'strict $.track.segments[*].location');
 jsonb_path_query
-------------------
 [47.763, 13.4034]
 [47.706, 13.2635]

宽松模式的解包行为可能导致令人意外的结果。 例如, 下面这个使用 .** 访问器的查询会把每个 HR 值选中两次:

=> select jsonb_path_query(:'json', 'lax $.**.HR');
 jsonb_path_query
------------------
 73
 135
 73
 135

之所以如此, 是因为 .** 访问器既选中 segments 数组也选中它的每个元素, 而在使用宽松模式时 .HR 访问器会自动解包数组。 为了避免令人意外的结果, 我们建议只在严格模式下使用 .** 访问器。 下面的查询会把每个 HR 值只选中一次:

=> select jsonb_path_query(:'json', 'strict $.**.HR');
 jsonb_path_query
------------------
 73
 135

数组的解包也可能导致意外的结果。 考虑这个选择全部 location 数组的例子:

=> select jsonb_path_query(:'json', 'lax $.track.segments[*].location');
 jsonb_path_query
-------------------
 [47.763, 13.4034]
 [47.706, 13.2635]
(2 rows)

正如预期的那样, 它返回完整的数组。 但应用一个过滤表达式会导致数组被解包以对每一项求值, 只返回与表达式相匹配的项:

=> select jsonb_path_query(:'json', 'lax $.track.segments[*].location ?(@[*] > 15)');
 jsonb_path_query
------------------
 47.763
 47.706
(2 rows)

尽管路径表达式选择的是完整的数组, 情况仍然如此。 使用严格模式可以恢复选择数组:

=> select jsonb_path_query(:'json', 'strict $.track.segments[*].location ?(@[*] > 15)');
 jsonb_path_query
-------------------
 [47.763, 13.4034]
 [47.706, 13.2635]
(2 rows)

9.16.2.3. SQL/JSON 路径操作符和方法 #

Table 9.52 展示了 jsonpath 中可用的操作符和方法。 注意,虽然一元操作符和方法可以应用于前一个路径步骤产生的多个值, 但二元操作符 (加法等) 只能应用于单值。 在宽松模式下, 应用到一个数组上的方法会对该数组中的每个值执行。 例外的是 .type() 和 .size(), 它们作用于数组本身。

Table 9.52. jsonpath 操作符和方法

操作符/方法

说明

示例

number + number → number

加法

jsonb_path_query('[2]', '$[0] + 3') → 5

+ number → number

一元加号 (不做任何操作); 与加法不同, 它可以迭代多个值

jsonb_path_query_array('{"x": [2,3,4]}', '+ $.x') → [2, 3, 4]

number - number → number

减法

jsonb_path_query('[2]', '7 - $[0]') → 5

- number → number

取负; 与减法不同, 它可以迭代多个值

jsonb_path_query_array('{"x": [2,3,4]}', '- $.x') → [-2, -3, -4]

number * number → number

乘法

jsonb_path_query('[4]', '2 * $[0]') → 8

number / number → number

除法

jsonb_path_query('[8.5]', '$[0] / 2') → 4.2500000000000000

number % number → number

取模(余数)

jsonb_path_query('[32]', '$[0] % 10') → 2

value . type() → string

JSON 项的类型 (参见 json_typeof)

jsonb_path_query_array('[1, "2", {}]', '$[*].type()') → ["number", "string", "object"]

value . size() → number

JSON 项的尺寸 (数组元素的数量, 如果不是数组则为 1)

jsonb_path_query('{"m": [11, 15]}', '$.m.size()') → 2

value . boolean() → boolean

从一个 JSON 布尔值、数字或字符串转换得到的布尔值

jsonb_path_query_array('[1, "yes", false]', '$[*].boolean()') → [true, true, false]

value . string() → string

从一个 JSON 布尔值、数字、 字符串或日期时间转换得到的字符串值

jsonb_path_query_array('[1.23, "xyz", false]', '$[*].string()') → ["1.23", "xyz", "false"]

jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp().string()') → "2023-08-15T12:34:56"

value . double() → number

从一个 JSON 数字或字符串转换得到的近似浮点数

jsonb_path_query('{"len": "1.9"}', '$.len.double() * 2') → 3.8

number . ceiling() → number

大于等于给定数字的最接近整数

jsonb_path_query('{"h": 1.3}', '$.h.ceiling()') → 2

number . floor() → number

小于等于给定数字的最接近整数

jsonb_path_query('{"h": 1.7}', '$.h.floor()') → 1

number . abs() → number

给定数字的绝对值

jsonb_path_query('{"z": -0.3}', '$.z.abs()') → 0.3

value . bigint() → bigint

从一个 JSON 数字或字符串转换得到的大整数值

jsonb_path_query('{"len": "9876543219"}', '$.len.bigint()') → 9876543219

value . decimal( [ precision [ , scale ] ] ) → decimal

从一个 JSON 数字或字符串转换得到的舍入十进制值 (precision 和 scale 必须是整数值)

jsonb_path_query('1234.5678', '$.decimal(6, 2)') → 1234.57

value . integer() → integer

从一个 JSON 数字或字符串转换得到的整数值

jsonb_path_query('{"len": "12345"}', '$.len.integer()') → 12345

value . number() → numeric

从一个 JSON 数字或字符串转换得到的数值

jsonb_path_query('{"len": "123.45"}', '$.len.number()') → 123.45

string . datetime() → datetime_type (see note)

从一个字符串转换得到的日期/时间值

jsonb_path_query('["2015-8-1", "2015-08-12"]', '$[*] ? (@.datetime() < "2015-08-2".datetime())') → "2015-8-1"

string . datetime(template) → datetime_type (see note)

使用指定的 to_timestamp 模板从字符串转换得到的日期/时间值

jsonb_path_query_array('["12:30", "18:40"]', '$[*].datetime("HH24:MI")') → ["12:30:00", "18:40:00"]

string . date() → date

从一个字符串转换得到的日期值

jsonb_path_query('"2023-08-15"', '$.date()') → "2023-08-15"

string . time() → time without time zone

从一个字符串转换得到的不带时区的时间值

jsonb_path_query('"12:34:56"', '$.time()') → "12:34:56"

string . time(precision) → time without time zone

从一个字符串转换得到的不带时区的时间值, 小数秒被调整到给定的精度

jsonb_path_query('"12:34:56.789"', '$.time(2)') → "12:34:56.79"

string . time_tz() → time with time zone

从一个字符串转换得到的带时区的时间值

jsonb_path_query('"12:34:56 +05:30"', '$.time_tz()') → "12:34:56+05:30"

string . time_tz(precision) → time with time zone

从一个字符串转换得到的带时区的时间值, 小数秒被调整到给定的精度

jsonb_path_query('"12:34:56.789 +05:30"', '$.time_tz(2)') → "12:34:56.79+05:30"

string . timestamp() → timestamp without time zone

从一个字符串转换得到的不带时区的时间戳值

jsonb_path_query('"2023-08-15 12:34:56"', '$.timestamp()') → "2023-08-15T12:34:56"

string . timestamp(precision) → timestamp without time zone

从一个字符串转换得到的不带时区的时间戳值, 小数秒被调整到给定的精度

jsonb_path_query('"2023-08-15 12:34:56.789"', '$.timestamp(2)') → "2023-08-15T12:34:56.79"

string . timestamp_tz() → timestamp with time zone

从一个字符串转换得到的带时区的时间戳值

jsonb_path_query('"2023-08-15 12:34:56 +05:30"', '$.timestamp_tz()') → "2023-08-15T12:34:56+05:30"

string . timestamp_tz(precision) → timestamp with time zone

从一个字符串转换得到的带时区的时间戳值, 小数秒被调整到给定的精度

jsonb_path_query('"2023-08-15 12:34:56.789 +05:30"', '$.timestamp_tz(2)') → "2023-08-15T12:34:56.79+05:30"

object . keyvalue() → array

该对象的键值对, 表示为一个由对象组成的数组, 每个对象包含三个字段: "key"、 "value" 和 "id"; "id" 是该键值对所属对象的唯一标识符

jsonb_path_query_array('{"x": "20", "y": 32}', '$.keyvalue()') → [{"id": 0, "key": "x", "value": "20"}, {"id": 0, "key": "y", "value": 32}]


Note

datetime() 和 datetime(template) 方法的结果类型可以是 date、 timetz、 time、 timestamptz 或 timestamp。 两种方法都会动态地确定它们的结果类型。

datetime() 方法会依次尝试把它的输入字符串与 date、 timetz、 time、 timestamptz 和 timestamp 的 ISO 格式相匹配。 它在第一个匹配的格式上停止, 并发出相应的数据类型。

datetime(template) 方法根据所提供模板字符串中使用的字段来确定结果类型。

datetime() 和 datetime(template) 方法使用的解析规则与 to_timestamp SQL 函数相同 (参见 Section 9.8), 有三个例外。 首先, 这些方法不允许不匹配的模板模式。 其次, 模板字符串中只允许以下分隔符: 减号、句点、斜杠 (solidus)、逗号、单引号、 分号、冒号和空格。 第三, 模板字符串中的分隔符必须与输入字符串精确匹配。

如果需要比较不同的日期/时间类型, 会应用一次隐式转换。 一个 date 值可以被转换为 timestamp 或 timestamptz, timestamp 可以被转换为 timestamptz, time 可以被转换为 timetz。 然而, 这些转换中除第一个之外, 其他都依赖于当前的 TimeZone 设置, 因此只能在时区感知的 jsonpath 函数内执行。 类似地, 其他把字符串转换为日期/时间类型的与日期/时间相关的方法也会做这样的转换, 这可能涉及当前的 TimeZone 设置。 因此, 这些转换同样只能在时区感知的 jsonpath 函数内执行。

Table 9.53 展示了可用的过滤表达式元素。

Table 9.53. jsonpath 过滤表达式元素

谓词/值

说明

示例

value == value → boolean

相等比较 (它以及其他比较操作符对所有 JSON 标量值都有效)

jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == 1)') → [1, 1]

jsonb_path_query_array('[1, "a", 1, 3]', '$[*] ? (@ == "a")') → ["a"]

value != value → boolean

value <> value → boolean

不等比较

jsonb_path_query_array('[1, 2, 1, 3]', '$[*] ? (@ != 1)') → [2, 3]

jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <> "b")') → ["a", "c"]

value < value → boolean

小于比较

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ < 2)') → [1]

value <= value → boolean

小于等于比较

jsonb_path_query_array('["a", "b", "c"]', '$[*] ? (@ <= "b")') → ["a", "b"]

value > value → boolean

大于比较

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ > 2)') → [3]

value >= value → boolean

大于等于比较

jsonb_path_query_array('[1, 2, 3]', '$[*] ? (@ >= 2)') → [2, 3]

true → boolean

JSON 常量 true

jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == true)') → {"name": "Chris", "parent": true}

false → boolean

JSON 常量 false

jsonb_path_query('[{"name": "John", "parent": false}, {"name": "Chris", "parent": true}]', '$[*] ? (@.parent == false)') → {"name": "John", "parent": false}

null → value

JSON 常量 null (注意, 与 SQL 不同, 与 null 的比较正常工作)

jsonb_path_query('[{"name": "Mary", "job": null}, {"name": "Michael", "job": "driver"}]', '$[*] ? (@.job == null) .name') → "Mary"

boolean && boolean → boolean

布尔与

jsonb_path_query('[1, 3, 7]', '$[*] ? (@ > 1 && @ < 5)') → 3

boolean || boolean → boolean

布尔或

jsonb_path_query('[1, 3, 7]', '$[*] ? (@ < 1 || @ > 5)') → 7

! boolean → boolean

布尔非

jsonb_path_query('[1, 3, 7]', '$[*] ? (!(@ < 5))') → 7

boolean is unknown → boolean

测试一个布尔条件是否为 unknown。

jsonb_path_query('[-1, 2, 7, "foo"]', '$[*] ? ((@ > 0) is unknown)') → "foo"

string like_regex string [ flag string ] → boolean

测试第一个操作数是否匹配由第二个操作数给定的正则表达式, 可以带由一个 flag 字符串描述的修改 (参见 Section 9.16.2.4)。

jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c")') → ["abc", "abdacb"]

jsonb_path_query_array('["abc", "abd", "aBdC", "abdacb", "babc"]', '$[*] ? (@ like_regex "^ab.*c" flag "i")') → ["abc", "aBdC", "abdacb"]

string starts with string → boolean

测试第二个操作数是否为第一个操作数的初始子串。

jsonb_path_query('["John Smith", "Mary Stone", "Bob Johnson"]', '$[*] ? (@ starts with "John")') → "John Smith"

exists ( path_expression ) → boolean

测试一个路径表达式是否匹配至少一个 SQL/JSON 项。 如果路径表达式会导致错误, 则返回 unknown; 第二个例子利用这一点来避免严格模式下的 no-such-key 错误。

jsonb_path_query('{"x": [1, 2], "y": [2, 4]}', 'strict $.* ? (exists (@ ? (@[*] > 2)))') → [2, 4]

jsonb_path_query_array('{"value": 41}', 'strict $ ? (exists (@.name)) .name') → []


9.16.2.4. SQL/JSON 正则表达式 #

SQL/JSON 路径表达式允许用 like_regex 过滤器把文本与正则表达式相匹配。 例如, 下面这条 SQL/JSON 路径查询会不区分大小写地匹配一个数组中以英语元音开头的所有字符串:

$[*] ? (@ like_regex "^[aeiou]" flag "i")

可选的 flag 字符串可以包括以下字符中的一个或多个: i 表示不区分大小写的匹配, m 允许 ^ 和 $ 在换行处匹配, s 允许 . 匹配换行符, q 把整个模式加引号 (把行为简化为一次简单的子串匹配)。

SQL/JSON 标准借用 LIKE_REGEX 操作符的正则表达式定义, 而后者又使用 XQuery 标准。 PostgreSQL 目前不支持 LIKE_REGEX 操作符。 因此, like_regex 过滤器是使用 Section 9.7.3 中描述的 POSIX 正则表达式引擎实现的。 这导致与标准 SQL/JSON 行为的各种细微差异, 这些差异被编目在 Section 9.7.3.8 中。 不过请注意, 那里描述的标志字母不兼容之处不适用于 SQL/JSON, 因为它会把 XQuery 的标志字母翻译为 POSIX 引擎期望的形式。

请记住, like_regex 的模式参数是一个 JSON 路径字符串字面量, 它按照 Section 8.14.7 中给出的规则书写。 这特别意味着, 你想在正则表达式中使用的任何反斜杠都必须写成双份。 例如, 要匹配根文档中只包含数字的字符串值:

$.* ? (@ like_regex "^\\d+$")

9.16.3. SQL/JSON 查询函数 #

Table 9.54 中描述的 SQL/JSON 函数 JSON_EXISTS()、 JSON_QUERY() 和 JSON_VALUE() 可用于查询 JSON 文档。 这些函数中的每一个都会把一个 path_expression (一条 SQL/JSON 路径查询) 应用到一个 context_item (即文档)上。 关于 path_expression 可以包含什么内容的更多细节, 请参见 Section 9.16.2。 path_expression 还可以引用变量, 变量的值由每个函数所支持的 PASSING 子句中以它们各自的名字指定。 context_item 可以是一个 jsonb 值, 或者一个可以被成功转换为 jsonb 的字符串。

Table 9.54. SQL/JSON 查询函数

函数签名

说明

示例

JSON_EXISTS (
context_item, path_expression
[ PASSING { value AS varname } [, ...]]
[{ TRUE | FALSE | UNKNOWN | ERROR } ON ERROR ]) → boolean

  • 如果应用到 context_item 上的 SQL/JSON path_expression 产生了任何项, 则返回真, 否则返回假。

  • ON ERROR 子句规定在 path_expression 求值期间发生错误时的行为。 指定 ERROR 会导致抛出一个带有适当消息的错误。 其他选项包括返回 boolean 值 FALSE 或 TRUE, 或者值 UNKNOWN, 它实际上是一个 SQL NULL。 在未指定 ON ERROR 子句时, 默认行为是返回 boolean 值 FALSE。

Examples:

JSON_EXISTS(jsonb '{"key1": [1,2,3]}', 'strict $.key1[*] ? (@ > $x)' PASSING 2 AS x) → t

JSON_EXISTS(jsonb '{"a": [1,2,3]}', 'lax $.a[5]' ERROR ON ERROR) → f

JSON_EXISTS(jsonb '{"a": [1,2,3]}', 'strict $.a[5]' ERROR ON ERROR) →

ERROR:  jsonpath array subscript is out of bounds

JSON_QUERY (
context_item, path_expression
[ PASSING { value AS varname } [, ...]]
[ RETURNING data_type [ FORMAT JSON [ ENCODING UTF8 ] ] ]
[ { WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ ARRAY ] WRAPPER ]
[ { KEEP | OMIT } QUOTES [ ON SCALAR STRING ] ]
[ { ERROR | NULL | EMPTY { [ ARRAY ] | OBJECT } | DEFAULT expression } ON EMPTY ]
[ { ERROR | NULL | EMPTY { [ ARRAY ] | OBJECT } | DEFAULT expression } ON ERROR ]) → jsonb

  • 返回把 SQL/JSON path_expression 应用到 context_item 上的结果。

  • 默认情况下, 结果作为 jsonb 类型的值返回, 不过可以使用 RETURNING 子句, 以某个它能被成功转换成的其他类型返回。

  • 如果路径表达式可能返回多个值, 可能需要使用 WITH WRAPPER 子句把这些值包装起来, 使它成为一个有效的 JSON 字符串, 因为默认的行为是不包装它们, 就像指定了 WITHOUT WRAPPER 一样。 WITH WRAPPER 子句默认被理解为 WITH UNCONDITIONAL WRAPPER, 这意味着即使是单一的结果值也会被包装。 要只在存在多个值时应用包装, 请指定 WITH CONDITIONAL WRAPPER。 如果指定了 WITHOUT WRAPPER, 那么结果中出现多个值将被视为一个错误。

  • 如果结果是一个标量字符串, 默认情况下返回的值会被引号环绕, 使它成为一个有效的 JSON 值。 可以通过指定 KEEP QUOTES 把这一点变得显式。 反过来, 可以通过指定 OMIT QUOTES 来省略引号。 为了确保结果是一个有效的 JSON 值, 当同时指定了 WITH WRAPPER 时, 不能指定 OMIT QUOTES。

  • ON EMPTY 子句规定当对 path_expression 的求值产生一个空集时的行为。 ON ERROR 子句规定当对 path_expression 的求值发生错误、 在把结果值转换为 RETURNING 类型时发生错误、 或者当 path_expression 的求值返回一个空集而对 ON EMPTY 表达式求值时发生错误的情况下的行为。

  • 对于 ON EMPTY 和 ON ERROR, 指定 ERROR 会导致抛出一个带有适当消息的错误。 其他选项包括返回一个 SQL NULL、 一个空数组 (EMPTY [ARRAY])、 一个空对象 (EMPTY OBJECT), 或一个用户指定的表达式 (DEFAULT expression), 它可以被转换成 jsonb 或 RETURNING 中指定的类型。 在未指定 ON EMPTY 或 ON ERROR 时, 默认行为是返回一个 SQL NULL 值。

Examples:

JSON_QUERY(jsonb '[1,[2,3],null]', 'lax $[*][$off]' PASSING 1 AS off WITH CONDITIONAL WRAPPER) → 3

JSON_QUERY(jsonb '{"a": "[1, 2]"}', 'lax $.a' OMIT QUOTES) → [1, 2]

JSON_QUERY(jsonb '{"a": "[1, 2]"}', 'lax $.a' RETURNING int[] OMIT QUOTES ERROR ON ERROR) →

ERROR:  malformed array literal: "[1, 2]"
DETAIL:  Missing "]" after array dimensions.

JSON_VALUE (
context_item, path_expression
[ PASSING { value AS varname } [, ...]]
[ RETURNING data_type ]
[ { ERROR | NULL | DEFAULT expression } ON EMPTY ]
[ { ERROR | NULL | DEFAULT expression } ON ERROR ]) → text

  • 返回把 SQL/JSON path_expression 应用到 context_item 上的结果。

  • 只有当被提取的值预期是一个单一的 SQL/JSON 标量项时才使用 JSON_VALUE(); 得到多个值将被视为一个错误。 如果你预期被提取的值可能是一个对象或数组, 请改用 JSON_QUERY 函数。

  • 默认情况下, 结果 (它必须是一个单一的标量值) 会作为 text 类型的值返回, 不过可以使用 RETURNING 子句, 以某个它能被成功转换成的其他类型返回。

  • ON ERROR 和 ON EMPTY 子句的语义与 JSON_QUERY 的描述中提到的类似, 只是代替抛出错误而返回的值的集合不同。

  • 注意, JSON_VALUE 返回的标量字符串总是会被去掉引号, 等同于在 JSON_QUERY 中指定 OMIT QUOTES。

Examples:

JSON_VALUE(jsonb '"123.45"', '$' RETURNING float) → 123.45

JSON_VALUE(jsonb '"03:04 2015-02-01"', '$.datetime("HH24:MI YYYY-MM-DD")' RETURNING date) → 2015-02-01

JSON_VALUE(jsonb '[1,2]', 'strict $[$off]' PASSING 1 as off) → 2

JSON_VALUE(jsonb '[1,2]', 'strict $[*]' DEFAULT 9 ON ERROR) → 9


Note

如果 context_item 表达式还不是 jsonb 类型, 它会通过一次隐式转换被转换为 jsonb。 不过请注意, 该转换期间发生的任何解析错误都会被无条件地抛出, 也就是说, 它们不会按照 (指定的或隐式的) ON ERROR 子句处理。

Note

如果 path_expression 返回一个 JSON null, JSON_VALUE() 会返回一个 SQL NULL, 而 JSON_QUERY() 会原样返回那个 JSON null。

9.16.4. JSON_TABLE #

JSON_TABLE 是一个 SQL/JSON 函数, 它查询 JSON 数据, 并把结果呈现为一个关系视图, 该视图可以作为一张普通的 SQL 表来访问。 你可以在 SELECT、 UPDATE 或 DELETE 的 FROM 子句中, 以及在 MERGE 语句中作为数据源使用 JSON_TABLE。

JSON_TABLE 以 JSON 数据为输入, 它使用一个 JSON 路径表达式来提取所提供数据的一部分, 作为所构造视图的 行模式。 行模式给出的每个 SQL/JSON 值都作为所构造视图中一个单独行的来源。

为了把行模式拆分成列, JSON_TABLE 提供了 COLUMNS 子句, 它定义所创建视图的模式。 对于每一列, 可以指定一个单独的 JSON 路径表达式, 针对行模式求值, 以得到一个 SQL/JSON 值, 它将成为给定输出行中指定列的值。

存储在行模式嵌套层级上的 JSON 数据可以用 NESTED PATH 子句来提取。 每个 NESTED PATH 子句都可以利用行模式嵌套层级上的数据生成一列或多列。 这些列可以用一个 COLUMNS 子句指定, 它看起来与顶层的 COLUMNS 子句类似。 由 NESTED COLUMNS 构造的行被称为 子行, 它们与由父 COLUMNS 子句中指定的列构造的行相连接, 以得到最终视图中的行。 子列自身也可以包含一个 NESTED PATH 说明, 从而允许提取位于任意嵌套层级上的数据。 由同一层级上的多个 NESTED PATH 产生的列被认为是彼此的 兄弟, 它们与父行连接之后的行会用 UNION 合并。

JSON_TABLE 产生的行会横向连接到产生它们的行, 因此你不必显式地把所构造的视图与持有 JSON 数据的原始表连接。

The syntax is:

JSON_TABLE (
    context_item, path_expression [ AS json_path_name ] [ PASSING { value AS varname } [, ...] ]
    COLUMNS ( json_table_column [, ...] )
    [ { ERROR | EMPTY [ARRAY]} ON ERROR ]
)


where json_table_column is:

  name FOR ORDINALITY
  | name type
        [ FORMAT JSON [ENCODING UTF8]]
        [ PATH path_expression ]
        [ { WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ ARRAY ] WRAPPER ]
        [ { KEEP | OMIT } QUOTES [ ON SCALAR STRING ] ]
        [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULT expression } ON EMPTY ]
        [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULT expression } ON ERROR ]
  | name type EXISTS [ PATH path_expression ]
        [ { ERROR | TRUE | FALSE | UNKNOWN } ON ERROR ]
  | NESTED [ PATH ] path_expression [ AS json_path_name ] COLUMNS ( json_table_column [, ...] )

下面会更详细地描述每个语法元素。

context_item, path_expression [ AS json_path_name ] [ PASSING { value AS varname } [, ...]]

context_item 指定要查询的输入文档, path_expression 是定义查询的一条 SQL/JSON 路径表达式, 而 json_path_name 是该 path_expression 的一个可选名字。 可选的 PASSING 子句为 path_expression 中提到的变量提供数据值。 用上述元素对输入数据求值的结果被称为 行模式, 它被用作所构造视图中行值的来源。

COLUMNS ( json_table_column [, ...] )

定义所构造视图模式的 COLUMNS 子句。 在这个子句中, 你可以指定每一列都填充一个通过把 JSON 路径表达式应用于行模式而得到的 SQL/JSON 值。 json_table_column 有以下这些变体:

name FOR ORDINALITY

添加一个序号列, 它提供从 1 开始的顺序行编号。 每个 NESTED PATH (见下文) 都会为任何嵌套的序号列准备它自己的计数器。

name type [FORMAT JSON [ENCODING UTF8]] [ PATH path_expression ]

把通过针对行模式应用 path_expression 得到的 SQL/JSON 值, 在把它转换为指定的 type 之后插入视图的输出行。

指定 FORMAT JSON 显式表明你期望该值是一个有效的 json 对象。 只有当 type 是 bpchar、 bytea、 character varying、 name、 json、 jsonb、 text, 或这些类型之上的一个域时, 指定 FORMAT JSON 才有意义。

可选地, 你可以指定 WRAPPER 和 QUOTES 子句来格式化输出。 注意, 如果同时指定了 OMIT QUOTES, 它会覆盖 FORMAT JSON, 因为不带引号的字面量不构成有效的 json 值。

可选地, 你可以使用 ON EMPTY 和 ON ERROR 子句, 分别规定当 JSON 路径求值的结果为空时、 以及在 JSON 路径求值期间或把 SQL/JSON 值转换为指定类型时发生错误时, 是抛出错误还是返回指定的值。 两者的默认行为都是返回一个 NULL 值。

Note

这个子句在内部被转换并且具有与 JSON_VALUE 或 JSON_QUERY 相同的语义。 当指定的类型不是一个标量类型, 或者存在 FORMAT JSON、 WRAPPER 或 QUOTES 子句之一时, 用的是后者。

name type EXISTS [ PATH path_expression ]

把通过针对行模式应用 path_expression 得到的布尔值, 在把它转换为指定的 type 之后插入视图的输出行。

该值对应于把 PATH 表达式应用到行模式上是否会产生任何值。

指定的 type 应当有一个从 boolean 类型出发的转换。

可选地, 你可以使用 ON ERROR 来规定当 JSON 路径求值期间或把 SQL/JSON 值转换为指定类型时发生错误时, 是抛出错误还是返回指定的值。 默认行为是返回布尔值 FALSE。

Note

这个子句在内部被转换并且具有与 JSON_EXISTS 相同的语义。

NESTED [ PATH ] path_expression [ AS json_path_name ] COLUMNS ( json_table_column [, ...] )

从行模式的嵌套层级中提取 SQL/JSON 值, 按照 COLUMNS 子子句的定义生成一列或多列, 并把提取到的 SQL/JSON 值插入那些列。 COLUMNS 子子句中的 json_table_column 表达式使用与父 COLUMNS 子句中相同的语法。

NESTED PATH 语法是递归的, 因此你可以通过在彼此之内指定多个 NESTED PATH 子子句来深入多个嵌套层级。 它允许在单次函数调用中解开 JSON 对象和数组的层级结构, 而不是在一条 SQL 语句中串起多个 JSON_TABLE 表达式。

Note

在上文描述的 json_table_column 的每个变体中, 如果省略了 PATH 子句, 则使用路径表达式 $.name, 其中 name 是所提供的列名。

AS json_path_name

可选的 json_path_name 用作所提供的 path_expression 的标识符。 该名字必须是唯一的, 并且与列名不同。

{ ERROR | EMPTY } ON ERROR

可选的 ON ERROR 可用于规定在对顶层 path_expression 求值时如何处理错误。 如果你希望抛出错误, 请使用 ERROR; 如果希望返回一个空表 (即包含 0 行的表), 请使用 EMPTY。 注意, 这个子句不影响对列求值时发生的错误, 那种错误的行为取决于是否针对给定的列指定了 ON ERROR 子句。

示例

在接下来的例子中, 将会使用下面这张包含 JSON 数据的表:

CREATE TABLE my_films ( js jsonb );

INSERT INTO my_films VALUES (
'{ "favorites" : [
   { "kind" : "comedy", "films" : [
     { "title" : "Bananas",
       "director" : "Woody Allen"},
     { "title" : "The Dinner Game",
       "director" : "Francis Veber" } ] },
   { "kind" : "horror", "films" : [
     { "title" : "Psycho",
       "director" : "Alfred Hitchcock" } ] },
   { "kind" : "thriller", "films" : [
     { "title" : "Vertigo",
       "director" : "Alfred Hitchcock" } ] },
   { "kind" : "drama", "films" : [
     { "title" : "Yojimbo",
       "director" : "Akira Kurosawa" } ] }
  ] }');

下面的查询展示了如何使用 JSON_TABLE 把 my_films 表中的 JSON 对象转换为一个视图, 该视图包含原始 JSON 中键 kind、 title 和 director 所对应的列, 外加一个序号列:

SELECT jt.* FROM
 my_films,
 JSON_TABLE (js, '$.favorites[*]' COLUMNS (
   id FOR ORDINALITY,
   kind text PATH '$.kind',
   title text PATH '$.films[*].title' WITH WRAPPER,
   director text PATH '$.films[*].director' WITH WRAPPER)) AS jt;

 id |   kind   |             title              |             director
----+----------+--------------------------------+----------------------------------
  1 | comedy   | ["Bananas", "The Dinner Game"] | ["Woody Allen", "Francis Veber"]
  2 | horror   | ["Psycho"]                     | ["Alfred Hitchcock"]
  3 | thriller | ["Vertigo"]                    | ["Alfred Hitchcock"]
  4 | drama    | ["Yojimbo"]                    | ["Akira Kurosawa"]
(4 rows)

下面是上面查询的一个修改版本, 用于展示在顶层 JSON 路径表达式中指定的过滤器里使用 PASSING 参数, 以及各个列的各种选项:

SELECT jt.* FROM
 my_films,
 JSON_TABLE (js, '$.favorites[*] ? (@.films[*].director == $filter)'
   PASSING 'Alfred Hitchcock' AS filter
     COLUMNS (
     id FOR ORDINALITY,
     kind text PATH '$.kind',
     title text FORMAT JSON PATH '$.films[*].title' OMIT QUOTES,
     director text PATH '$.films[*].director' KEEP QUOTES)) AS jt;

 id |   kind   |  title  |      director
----+----------+---------+--------------------
  1 | horror   | Psycho  | "Alfred Hitchcock"
  2 | thriller | Vertigo | "Alfred Hitchcock"
(2 rows)

下面是上面查询的一个修改版本, 用于展示使用 NESTED PATH 来填充 title 和 director 列, 并说明它们是如何与父列 id 和 kind 相连接的:

SELECT jt.* FROM
 my_films,
 JSON_TABLE ( js, '$.favorites[*] ? (@.films[*].director == $filter)'
   PASSING 'Alfred Hitchcock' AS filter
   COLUMNS (
    id FOR ORDINALITY,
    kind text PATH '$.kind',
    NESTED PATH '$.films[*]' COLUMNS (
      title text FORMAT JSON PATH '$.title' OMIT QUOTES,
      director text PATH '$.director' KEEP QUOTES))) AS jt;

 id |   kind   |  title  |      director
----+----------+---------+--------------------
  1 | horror   | Psycho  | "Alfred Hitchcock"
  2 | thriller | Vertigo | "Alfred Hitchcock"
(2 rows)

下面是同一条查询, 但根路径中没有过滤器:

SELECT jt.* FROM
 my_films,
 JSON_TABLE ( js, '$.favorites[*]'
   COLUMNS (
    id FOR ORDINALITY,
    kind text PATH '$.kind',
    NESTED PATH '$.films[*]' COLUMNS (
      title text FORMAT JSON PATH '$.title' OMIT QUOTES,
      director text PATH '$.director' KEEP QUOTES))) AS jt;

 id |   kind   |      title      |      director
----+----------+-----------------+--------------------
  1 | comedy   | Bananas         | "Woody Allen"
  1 | comedy   | The Dinner Game | "Francis Veber"
  2 | horror   | Psycho          | "Alfred Hitchcock"
  3 | thriller | Vertigo         | "Alfred Hitchcock"
  4 | drama    | Yojimbo         | "Akira Kurosawa"
(5 rows)

下面展示了另一个查询, 它使用一个不同的 JSON 对象作为输入。 它展示了 NESTED 路径 $.movies[*] 和 $.books[*] 之间的 UNION “兄弟连接”, 以及 FOR ORDINALITY 列在 NESTED 层级上的使用 (列 movie_id、 book_id 和 author_id):

SELECT * FROM JSON_TABLE (
'{"favorites":
    [{"movies":
      [{"name": "One", "director": "John Doe"},
       {"name": "Two", "director": "Don Joe"}],
     "books":
      [{"name": "Mystery", "authors": [{"name": "Brown Dan"}]},
       {"name": "Wonder", "authors": [{"name": "Jun Murakami"}, {"name":"Craig Doe"}]}]
}]}'::json, '$.favorites[*]'
COLUMNS (
  user_id FOR ORDINALITY,
  NESTED '$.movies[*]'
    COLUMNS (
    movie_id FOR ORDINALITY,
    mname text PATH '$.name',
    director text),
  NESTED '$.books[*]'
    COLUMNS (
      book_id FOR ORDINALITY,
      bname text PATH '$.name',
      NESTED '$.authors[*]'
        COLUMNS (
          author_id FOR ORDINALITY,
          author_name text PATH '$.name'))));

 user_id | movie_id | mname | director | book_id |  bname  | author_id | author_name
---------+----------+-------+----------+---------+---------+-----------+--------------
       1 |        1 | One   | John Doe |         |         |           |
       1 |        2 | Two   | Don Joe  |         |         |           |
       1 |          |       |          |       1 | Mystery |         1 | Brown Dan
       1 |          |       |          |       2 | Wonder  |         1 | Jun Murakami
       1 |          |       |          |       2 | Wonder  |         2 | Craig Doe
(5 rows)