2024 年 9 月 26 日:PostgreSQL 17 已发布!
支持版本:当前 (17) / 16 / 15 / 14 / 13 / 12
开发版本:devel
不受支持的版本:11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2

9.16。 JSON 函数和运算符 #

本节介绍

  • 用于处理和创建 JSON 数据的函数和运算符

  • SQL/JSON 路径语言

  • SQL/JSON 查询函数

为了在 SQL 环境中提供 JSON 数据类型的本机支持,PostgreSQL 实现了SQL/JSON 数据模型。此模型包含一系列的项目。每个项目都可以包含 SQL 标量值,以及附加的 SQL/JSON null 值,以及使用 JSON 数组和对象的复合数据结构。该模型是 JSON 规范 RFC 7159 中暗示数据模型的形式化表达。

SQL/JSON 允许您处理 JSON 数据和常规 SQL 数据,并提供事务支持,包括

  • 正在数据库中上传 JSON 数据,并以上面或二进制字符串形式常规 SQL 列存储。

  • 从关系数据中生成 JSON 对象和数组。

  • 使用 SQL/JSON 查询函数和 SQL/JSON 路径语言表达式来查询 JSON 数据。

要详细了解 SQL/JSON 标准,请参见 [sqltr-19075-6]。如需详细了解 PostgreSQL 支持的 JSON 类型,请参见 8.14 节

9.16.1. 处理和创建 JSON 数据 #

表 9.45 显示了可用于 JSON 数据类型的运算符(请参见 8.14 节)。此外,表 9.1 中显示的常规比较运算符可用于 jsonb,但不可用于 json。比较运算符遵循 8.14.4 节 中概述的 B 树操作排序规则。另请参阅 9.21 节,了解如下内容:聚合函数 json_agg(将记录值聚合为 JSON)、聚合函数 json_object_agg(将值对聚合为 JSON 对象),以及它们对应的 jsonb 等效项 jsonb_aggjsonb_object_agg

表 9.45. jsonjsonb 运算符

运算符

说明

示例

json -> integerjson

jsonb -> integerjsonb

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

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

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

json -> textjson

jsonb -> textjsonb

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

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

json ->> integertext

jsonb ->> integertext

提取 JSON 数组的第 n 个元素,作为 text

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

json ->> text文本

jsonb ->> 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[]文本

jsonb #>> text[]文本

作为 文本,提取指定路径处的 JSON 子对象。

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


注意

如果 JSON 输入没有匹配请求的正确结构,字段/元素/路径提取运算符将返回 NULL 而不是失败;例如,如果不存在这样的键或数组元素。

某些其他运算符只存在于 jsonb 中,如 表 9.46 所示。 章节 8.14.4 描述了如何使用这些运算符有效搜索索引 jsonb 数据。

表 9.46。其他 jsonb 运算符

运算符

说明

示例

jsonb @> jsonb布尔

第一个 JSON 值是否包含第二个 JSON 值?(有关包含的详细信息,请参见章节 8.14.3。)

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

jsonb <@ jsonb布尔

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

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

jsonb ? text布尔

文本字符串是否作为顶级键或 JSON 值内的数组元素存在?

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

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

jsonb ?| text[]布尔

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

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

jsonb ?& text[]布尔值

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

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

jsonb || jsonbjsonb

连接两个 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 - textjsonb

从 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 - integerjsonb

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

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

jsonb #- text[]jsonb

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

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

jsonb @? jsonpath布尔值

JSON 路径为指定 JSON 值返回任意项目吗?(这仅与 SQL 标准 JSON 路径表达式而非谓词检查表达式谓词检查表达式一同使用时有用,因为后者始终返回一个值。)

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

jsonb @@ jsonpathboolean

返回针对指定 JSON 值的 JSON 路径谓词检查的结果。(这仅与谓词检查表达式而非 SQL 标准 JSON 路径表达式一同使用时有用,因为它将返回 NULL,如果路径结果不是一个单独的布尔值。)

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


注意

jsonpath 运算符 @?@@ 抑制以下错误:缺少对象字段或阵列元素、意外的 JSON 项目类型,以及日期时间和数字错误。jsonpath 相关函数(详情见下文)也可用于抑制这些类型的错误。该行为在搜索结构各异的 JSON 文档集合时可能会有用。

表格 9.47显示了可用于构建 jsonjsonb 值的函数。此表格中的某些函数具有一个 RETURNING 子句,该子句指定返回的数据类型。该子句必须是 jsonjsonbbytea、字符字符串类型(textcharvarchar)或可转换为 json 的类型。默认情况下,将返回 json 类型。

表格 9.47. JSON 创建函数

函数

说明

示例

to_json ( anyelement ) → json

to_jsonb ( anyelement ) → jsonb

将任何 SQL 值转换为 jsonjsonb。数组和复合类型会递归式转换为数组和对象(多维数组在 JSON 中变为数组的数组)。否则,如果 SQL 数据类型可以转换为 json,则会使用转换函数执行转换;[a] 否则,会生成一个标量 JSON 值。对于除数字、布尔或 null 值之外的任意标量,将使用文本表示形式,并按需要转义文本表示形式使其成为一个有效的 JSON 字符串值。

to_json('Fred 说 "Hi."'::text)"Fred 说 \"Hi.\""

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

array_to_json ( anyarray [, boolean ] ) → json

将 SQL 数组转换为 JSON 数组。如果可选布尔参数为 true,则行为与 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(必须是一个只返回一列的 SELECT 查询)的结果构建一个 JSON 数组。如果指定 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 对象。如果可选布尔参数为 true,则行为与 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_jsonto_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_jsonto_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 对象。数组必须具有恰好一个维度和偶数个成员,这种情况下,以它们作为交替的键值对;或者具有两个维度,使得每个内部数组恰好有 2 个元素,它们被视为键值对。所有值都转换 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

将指定为 textbytea 字符串的给定表达式(采用 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返回 null。如果输入是数字或布尔值,则返回相应的 JSON 数字或布尔值。对于任何其他值,则返回 JSON 字符串。

json_scalar(123.45)123.45

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

json_serialize ( 表达式 [ 格式 JSON [ 编码 UTF8 ] ] [ 返回 数据类型 [ 格式 JSON [ 编码 UTF8 ] ] ] )

将 SQL/JSON 表达式转换成字符或二进制字符串。 表达式 可以是任何 JSON 类型、任何字符类型字符串或 UTF8 编码下的 bytea返回 中使用的返回类型可以是任何字符类型字符串或 bytea。默认类型为 text

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

[a] 例如,hstore 扩展程序会将 hstore 转换为 json,因此,通过 JSON 创建函数转换成的 hstore 值会以 JSON 对象的形式显示,而不是以原始字符串值的形式显示。


第 9.48 表 详细介绍了用于测试 JSON 的 SQL/JSON 功能。

第 9.48 表。SQL/JSON 测试函数

函数签名

说明

示例

表达式 [ 并非 ] JSON [ { | 标量 | 数组 | 对象 } ] [ { 具有 | 不具有 } 唯一 [ ] ]

此谓词测试 表达式 是否可以解析为 JSON,它可以是指定类型。如果指定了 标量数组对象,则测试 JSON 是不是属于特定类型。如果指定了 具有唯一键,也将会测试 表达式 中的任何对象是否具有重复的键。

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

第 9.49 表 展示了可用于处理 jsonjsonb 值的函数。

第 9.49 表。JSON 处理函数

函数

说明

示例

json_array_elements ( json ) → 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 对象中键的 set。

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,这意味着在任何输出列中,与任何对象字段不匹配的列都将填充为 null 值。然而,如果 base 不为 NULL,则将使用它包含的值来填充与对象字段不匹配的列。

要将 JSON 值转换成输出列的 SQL 类型,将按如下顺序应用以下规则

  • 在所有情况下,JSON null 值都转换成 SQL null

  • 如果输出列的类型是 jsonjsonb,JSON 值只是被精确复制

  • 如果输出列是复合(行)类型,且 JSON 值是 JSON 对象,通过递归应用这些规则,将对象的字段转换成输出行类型的列

  • 同样,如果输出列是数组类型且 JSON 值是 JSON 数组,通过递归应用这些规则,将 JSON 数组的元素转换成输出数组的元素

  • 否则,如果 JSON 值是字符串,则将字符串的内容提供给该列数据类型的输入转换函数

  • 否则,将 JSON 值的普通文本表示形式提供给该列数据类型的输入转换函数

虽然以下示例使用了常量 JSON 值,但典型用法是在查询的 FROM 子句中从另一个表的某一 jsonjsonb 侧向引用一个列。在 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 的函数。如果输入 jsonb_populate_record 对于给定的输入 JSON 对象运行且不会出错,则返回 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 所述相同。由于没有输入记录值,因此不匹配的列始终填充为 null。

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 为 true(这是默认值),且由 path 指定的项不存在,则添加 new_value。路径中的所有早期步骤必须存在,否则 target 保持不变。与面向路径的操作符一样,出现在 path 中的负整数从 JSON 数组的末尾计数。如果最后一个路径步骤是一个超出范围的数组索引,并且 create_if_missing 为 true,则如果索引为负,则在数组的开头添加新值,否则如果索引为正,则在数组的末尾添加新值。

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_valuetarget。如果 path 指定的项是数组元素,如果 insert_after 为 false(这是默认值),则将在该项之前插入 new_value;如果 insert_after 为 true,则将在该项之后插入。如果 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 ( json ) → json

jsonb_strip_nulls ( jsonb ) → jsonb

从给定的 JSON 值中递归删除所有具有空值的字段。没有设定空值的字段不受影响。

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

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 标准 JSON 路径表达式,因为如果路径结果不是单个布尔值,它将失败或返回 NULL。)可选的 varssilent 参数与 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 值。对于 谓词检查表达式,它返回谓词检查的结果:truefalsenull。可选的 varssilent 参数与 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 作为带时区的 timestamp 进行解释,所以结果取决于当前设置的 TimeZone。因为存在此依赖性,所以这些函数被标记为 stable,这意味着不能在索引中使用这些函数。它们的对等函数不可变,因此可以在索引中使用;但如果要求进行此类比较,则它们将抛出错误。

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 值的类型作为文本字符串返回。可能的类型有 objectarraystringnumberbooleannull。(null 结果不应该与 SQL NULL 混淆;请参见示例。)

json_typeof('-123.4')number

json_typeof('null'::json)null

json_typeof(NULL::json) IS NULLt


9.16.2. SQL/JSON 路径语言 #

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

JSON 查询函数和运算符将提供的路径表达式传递给 路径引擎 评估。如果表达式与所查询的 JSON 数据匹配,则返回相应的 JSON 项或项集。如果没有匹配,则结果将为 NULLfalse 或错误(具体取决于函数)。路径表达式用 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]

每个路径评估步骤的结果都可以由 第 9.16.2.3 部分 中列出的一个或多个 jsonpath 运算符和方法处理。每个方法名称之前必须加上一个点。例如,您可以获取数组的大小。

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

下面在 第 9.16.2.3 部分 中显示了使用路径表达式中的 jsonpath 运算符和方法的其他示例。

路径还可以包含筛选表达式,其工作原理类似于 SQL 中的 WHERE 子句。筛选表达式以问号开头,并在括号中提供一个条件。

? (condition)

必须在应应用筛选表达式的路径评估步骤后立即编写筛选表达式。该步骤的结果会进行筛选,仅包括满足所提供条件的那些项。SQL/JSON 定义了三值逻辑,所以条件可以生成 truefalseunknownunknown 值扮演与 SQL NULL 相同的角色,并且可以使用谓词 is unknown 对其进行测试。后续路径评估步骤只使用筛选表达式返回 true 的那些项。

可以在筛选表达式中使用的函数和运算符列在 表 9.51 中。在筛选表达式内,@ 变量表示正在考虑的值(即前一路径步骤的一个结果)。您可以在 @ 后编写访问器运算符来检索组件项。

例如,假设您想要检索所有高于 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"

如果需要,您可以在序列中使用多个筛选表达式。下面的示例选择 start 时间为包含具有相关坐标和高心率值的位置的所有段。

=> 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 值的相关元素,但谓词判断表达式返回谓词的单个三值结果:truefalseunknown。例如,我们可以编写以下符合 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

注意

```code``` 运算符(以及 jsonb_path_match 函数)需要谓词判断表达式,并且不应与 @? 运算符(或 jsonb_path_exists 函数)一起使用。

9.16.2.1.2. 正则表达式解释 #

like_regex 过滤器中使用的正则表达式模式的解释有一些细微差异,如 第 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 路径运算符和方法 #

表 9.50 显示了 jsonpath 中可用的运算符和方法。请注意,虽然一元运算符和方法可应用于从前一路径步骤产生的多个值,但二元运算符(加法等)只能应用于单个值。在宽松模式下,应用于数组的方法将针对数组中的每个值执行。例外是 .type().size(),后者适用于数组本身。

表 9.50. jsonpath 运算符和方法

运算符/方法

说明

示例

number + numbernumber

加法

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

+ numbernumber

一元加法(无操作); 与加法不同,此操作可以迭代多个值

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

number - numbernumber

减法

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

- numbernumber

求负数;与减法不同,这里可以对多个值重复迭代

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

number * numbernumber

求积

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

number / numbernumber

求商

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

number % numbernumber

取模(取余)

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

数字 . floor()数字

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

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

数字 . abs()数字

给定数字的绝对值

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

. bigint()大整数

从 JSON 数字或字符串中转换得到的大整数

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

. decimal( [ 精度 [ , 小数位 ] ] )十进制

从 JSON 数字或字符串中转换得到的舍入十进制值(精度小数位必须为整数值)

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

. integer()整数

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

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

. number()数字

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

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

字符串 . datetime()日期时间类型 (见注释)

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

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

字符串 . datetime(模板)日期时间类型 (见注释)

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

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

字符串 . 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

无时区的 Timestamp 值从字符串转换

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

string . timestamp(precision)timestamp without time zone

无时区的 Timestamp 值从字符串转换,小数秒会被调整至给定的精度

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

有时区的 Timestamp 值从字符串转换

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

有时区的 Timestamp 值从字符串转换,小数秒会被调整至给定的精度

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}]


注意

datetime()datetime(template) 方法的结果类型可以是 datetimetztimetimestamptztimestamp。这两种方法都会动态地确定其结果类型。

datetime() 方法顺序尝试将输入字符串与 datetimetztimetimestamptztimestamp 的 ISO 格式进行匹配。它会在第一个匹配的格式中停止并发出相应的数据类型。

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

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

如果需要比较不同的日期/时间类型,则应用隐式强制转换。date 值可以强制转换为 timestamptimestamptztimestamp 可以强制转换为 timestamptztime 可以强制转换为 timetz。但是,除了第一个之外的所有这些转换都取决于当前 TimeZone 设置,因此只能在支持时区的 jsonpath 函数中执行。类似地,其他将字符串转换为日期/时间类型的日期/时间相关方法也会执行此强制转换,其中可能涉及当前的 TimeZone 设置。因此,这些转换也只可在支持时区的 jsonpath 函数中执行。

表 9.51 显示了可用的过滤器表达式元素。

表 9.51。jsonpath 过滤器表达式元素

谓词/值

说明

示例

== 布尔值

相等性比较(此运算符以及其他比较运算符适用于所有 JSON 标量值)

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

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

!= 布尔值

<> 布尔值

不等于比较

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

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

< 布尔值

小于比较

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

<= 布尔值

小于或等于比较

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

> 布尔值

大于比较

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

>= 布尔值

大于或等于比较

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

true布尔值

JSON 常量 true

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

false布尔值

JSON 常量 false

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

null

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

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

布尔值 && 布尔值布尔值

布尔且

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

boolean || booleanboolean

布尔 OR

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

! booleanboolean

布尔 NOT

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

boolean is unknownboolean

测试布尔条件是否为 unknown

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

string like_regex string [ flag string ] → boolean

测试第一个操作数是否与第二个操作数给出的正则表达式匹配,可通过一系列 flag 字符(参见 第九章 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 stringboolean

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

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

exists ( path_expression )boolean

测试一个路径表达式是否匹配至少一个 SQL/JSON 元素。如果路径表达式将导致错误,则返回 unknown;第二个示例使用此表达式以在严格模式下避免键不存在的错误。

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 运算符借用其正则表达式的定义,而 LIKE_REGEX 运算符又使用 XQuery 标准。PostgreSQL 当前不支持 LIKE_REGEX 运算符。因此,like_regex 过滤器使用 第 9.7.3 节中描述的 POSIX 正则表达式引擎实现。这会导致与标准 SQL/JSON 行为的各种细微差异,这些差异在 第 9.7.3.8 节 中编入目录。但请注意,此处描述的标志字母不兼容的情况不适用于 SQL/JSON,因为它会将 XQuery 标志字母转换为 POSIX 引擎期望的内容。

请记住,like_regex 的模式参数是 JSON 路径字符串文本,根据 第 8.14.7 节 中给出的规则编写。这意味着您要在正则表达式中使用的任何反斜杠都必须加倍。例如,要匹配仅包含数字的根文档字符串值,则

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

9.16.3. SQL/JSON 查询函数 #

表 9.52 中描述的 SQL/JSON 函数 JSON_EXISTS()JSON_QUERY()JSON_VALUE() 可用于查询 JSON 文档。这些函数每个都会将path_expression(SQL/JSON 路径查询)应用于context_item(文档)。有关path_expression 可以包含什么的更多详细信息,请参见 第 9.16.2 节path_expression 还可以引用变量,其值在每个函数支持的 PASSING 子句中用其各自的名称指定。context_item 可以是 jsonb 值或可以成功转换到 jsonb 的字符串。

表 9.52. 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 产生任何项,则返回 true,否则返回 false。

  • 如果在评估路径表达式时发生错误,ON ERROR 子句将指定行为。指定 ERROR 将导致抛出一个具有适当消息的错误。其他选项包括返回 booleanFALSETRUE 或实际上是 SQL NULL 的值 UNKNOWN。未指定 ON ERROR 子句时的默认值是返回 booleanFALSE

示例

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 路径表达式 应用于上下文项 的结果。

  • 默认情况下,结果作为类型为 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 子句将指定行为。当评估 路径表达式 时发生错误、将结果值强制转换为 RETURNING 类型,或者当 路径表达式 评估返回一个空集时评估 ON EMPTY 表达式,则 ON ERROR 子句将指定行为。

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

示例

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 路径表达式 应用于上下文项 的结果。

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

  • 默认情况下,结果(必须为单个标量值)作为 text 类型的值返回,尽管可以使用 RETURNING 子句作为可以成功强制转换到的其他类型返回。

  • ON ERRORON EMPTY 子句具有与 JSON_QUERY 说明中提及的类似语义,所不同的是,替代抛出错误而返回的值集不同。

  • 请注意,JSON_VALUE 返回的标量字符串始终会去除引号,相当于在 JSON_QUERY 中指定 OMIT QUOTES

示例

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


注意

context_item 表达式通过隐式强制转换转换为 jsonb,前提是该表达式不是已经属于 jsonb 类型。但是请注意,在此转换过程中发生的任何解析错误都会无条件地抛出,也就是说不会根据(指定的或隐式的)ON ERROR 子句进行处理。

注意

JSON_VALUE() 如果 path_expression 返回 JSON null,则返回 SQL NULL,而 JSON_QUERY() 原样返回 JSON null

9.16.4. JSON_TABLE

JSON_TABLE 是一个 SQL/JSON 函数,它查询JSON数据,并将结果显示为关系视图,可以像常规的 SQL 表一样访问。可以在 SELECTUPDATEDELETEFROM 子句中使用 JSON_TABLE,也可以将其用作 MERGE 语句中的数据源。

采用 JSON 数据作为输入时,JSON_TABLE 使用 JSON 路径表达式来提取提供的数据的一部分,并将其用作构造视图的 行模式。行模式给出的每个 SQL/JSON 值充当构造视图中的单独行的来源。

为将行模式分成多列,JSON_TABLE 提供了定义创建的视图的架构的 COLUMNS 子句。对于每一列,可以指定一个单独的 JSON 路径表达式,针对行模式对其进行求值,以获取将成为给定输出行中指定列值的 SQL/JSON 值。

可以使用 NESTED PATH 子句提取存储在行模式的嵌套级别的数据。每个 NESTED PATH 子句可用于使用来自行模式的嵌套级别的数据生成一列或多列。可以使用与顶级 COLUMNS 子句相似的 COLUMNS 子句指定这些列。由 NESTED COLUMNS 构造的行称为 子行,并且会与从父 COLUMNS 子句中指定的列构造的行联接,以获取最终视图中的行。子列本身可能包含 NESTED PATH 规范,从而允许提取位于任意嵌套级别的。同一级别由多个 NESTED PATH 产生的列被视为彼此的 兄弟,并且在与父行联接后,其行会使用 UNION 进行组合。

JSON_TABLE 产生的行横向联接到生成它们的行的旁边,因此不必显式地将构造的视图与包含JSON数据的原始表联接。

语法为

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_namepath_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 对象。只有在 typebpcharbyteacharacter varyingnamejsonjsonbtext 或这些类型的域的情况下,才合理指定 FORMAT JSON

另外,您可以指定 WRAPPERQUOTES 子句来设置输出格式。请注意,如果同时指定,OMIT QUOTES 会覆盖 FORMAT JSON,因为未加引号的常量不构成合法的 json 值。

另外,您可以使用 ON EMPTYON ERROR 子句来指定在 JSON 路径评估结果为空以及在 JSON 路径评估期间或在强制 SQL/JSON 值转换为指定类型时出现错误时的处理方式,分别抛出错误还是返回指定的值。两者的默认值均为返回 NULL 值。

注意

此子句在内部将转换为含义与 JSON_VALUEJSON_QUERY 相同的子句。如果指定了类型不是标量类型,或者如果 FORMAT JSONWRAPPERQUOTES 子句中任何一个已存在,则采用后一个子句。

name type EXISTS [ PATH path_expression ]

将通过针对行模式应用 path_expression 获得的布尔值插入到将该值强制转换为指定的 type 之后视图的输出行中。

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

指定的 type 应有从 boolean 类型进行强制转换。

您可以选择使用 ON ERROR 指定在 JSON 路径评估或 SQL/JSON 值强制转换为指定类型时发生错误时是引发错误还是返回指定值。默认操作是返回布尔值 FALSE

注意

此子句在内部将转换为含义与 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 表达式。

注意

在上面描述的每种 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_TABLEmy_films 表中的 JSON 对象转换为一个视图,该视图包含原始 JSON 中包含的键 kindtitledirector 的列以及一个序数列

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, 'Vertigo' AS filter2
     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_idbook_idauthor_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)

提交更正

如果您看到文档中的任何内容不正确,不符合您对特定功能的体验或需要进一步澄清,请使用 此表单 报告文档问题。