受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发版本: devel

9.16. JSON 函数和操作符 #

本节描述:

  • 用于处理和创建 JSON 数据的函数和操作符

  • SQL/JSON路径语言

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

9.16.1. 处理和创建 JSON 数据 #

Table 9.45显示了可用于 JSON 数据类型的操作符(参见Section 8.14)。 此外,Table 9.1中给出的常规比较操作符也可用于jsonb,但不适用于json。 比较操作符遵循 B-树操作的排序规则,详见Section 8.14.4。 另请参阅Section 9.21,了解聚合函数json_agg如何将记录值聚合为 JSON, 以及聚合函数json_object_agg如何将值对聚合为 JSON 对象,还有它们对应的jsonb函数, jsonb_aggjsonb_object_agg

Table 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 ->> texttext

jsonb ->> texttext

用给定的键提取JSON对象字段,作为text

'{"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

将指定路径上的JSON子对象提取为text

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


Note

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

还有一些操作符仅适用于jsonb,如表Table 9.46所示。 第Section 8.14.4描述了如何使用这些操作符来有效地搜索索引的jsonb数据。

Table 9.46. 附加的 jsonb 操作符

操作符

描述

示例

jsonb @> jsonbboolean

第一个JSON值是否包含第二个?(请参见Section 8.14.3以了解包含的详细信息。)

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

jsonb <@ jsonbboolean

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

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

jsonb ? textboolean

文本字符串是否作为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 || 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 @? jsonpathboolean

JSON路径是否为指定的JSON值返回任何项?

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

jsonb @@ jsonpathboolean

返回指定JSON值的JSON路径谓词检查的结果。只考虑结果的第一项。如果结果不是布尔值,则返回NULL

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


Note

jsonpath操作符@?@@抑制以下错误:缺少对象字段或数组元素,意外的JSON项目类型,日期时间和数字错误。 还可以告诉以下描述的与jsonpath相关的函数来抑制这些类型的错误。 在搜索不同结构的JSON文档集合时,此行为可能会有所帮助。

Table 9.47 显示可用于构造jsonjsonb值的函数。

Table 9.47. JSON 创建函数

函数

描述

示例

to_json ( anyelement ) → json

to_jsonb ( anyelement ) → jsonb

将任何SQL值转换为jsonjsonb。数组和组合递归地转换为数组和对象(多维数组在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相同,只是如果可选boolean参数为真,换行符将在顶级数组元素之间添加。

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

row_to_json ( record [, boolean ] ) → json

将SQL组合值转换为JSON对象。该行为与to_json相同,只是如果可选boolean参数为真,换行符将在顶级元素之间添加。

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 ( 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"}

[a] 例如,hstore扩展有一个从hstorejson的转换,这样通过json创建函数转换的hstore值将被表示为json对象,而不是原始字符串值


Table 9.48 显示可用于处理jsonjsonb值的函数。

Table 9.48. 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

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

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,这意味着任何不匹配对象字段的输出列都会被填充为 NULL。 但是,如果base不为NULL,那么它包含的值将用于不匹配的列。

要将JSON值转换为输出列的SQL类型,需要按次序应用以下规则:

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

  • 如果输出列的类型是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")

json_populate_recordset ( base anyelement, from_json json ) → setof anyelement

jsonb_populate_recordset ( base anyelement, from_json jsonb ) → setof anyelement

将对象的顶级 JSON 数组展开为一组具有 base 参数复合类型的行。 对于json[b]_populate_record,将如上所述处理JSON数组的每个元素。

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[b]_populate_record,将如上所述处理JSON数组的每个元素。

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。 与面向路径操作符一样,负整数出现在JSON数组末尾的path计数中。 如果最后一个路径步骤是超出范围的数组索引,并且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_valuetarget。 如果path指派的项是一个数组元素,如果 insert_after为假(此为默认值),则new_value将被插入到该项之前,如果 insert_after为真则在该项之后。 如果由path指派的项是一个对象字段,则只在对象不包含该键时才插入 new_value。 路径中的所有前面步骤都必须存在,否则将不加改变地返回target。 与面向路径操作符一样,负整数出现在JSON数组末尾的 path计数中。 如果最后一个路径步骤是超出范围的数组下标,则如果下标为负,则将新值添加到数组的开头;如果下标为正,则将新值添加到数组的结尾。

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值的任何项。如果指定了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路径谓词检查的结果。只有结果的第一项被考虑在内。 如果结果不是布尔值,则返回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项。可选的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项。可选的varssilent参数的作用与jsonb_path_exists相同。

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。 可选的varssilent参数的作用与 jsonb_path_exists相同。

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 NULLt


9.16.2. SQL/JSON 路径语言 #

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

JSON 查询函数和操作符会将给定的路径表达式传递给路径引擎进行求值。 如果表达式与被查询的JSON数据匹配,则返回相应的JSON项或项集。 路径表达式是用SQL/JSON路径语言编写的,也可以包括算术表达式和函数。

路径表达式由jsonpath数据类型允许的元素序列组成。路径表达式通常从左向右求值,但你可以使用圆括号来更改操作的顺序。 如果计算成功,将生成一系列JSON项,并将计算结果返回到JSON查询函数,该函数将完成指定的计算。

要引用正在查询的JSON值(context item项),在路径表达式中使用$变量。 它后面可以跟着一个或多个accessor operators,这些操作符在JSON结构中逐级向下检索上下文项的子项。 后面的每个操作符处理前一个求值步骤的结果。

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

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

为了检索可用的轨迹段,你需要使用.key访问操作符来向下浏览周边的JSON对象:

$.track.segments

要检索数组的内容,通常使用[*]操作符。例如,下面的路径将返回所有可用轨道段的位置坐标:

$.track.segments[*].location

要只返回第一个段的坐标,可以在[]访问操作符中指定相应的下标。重新调用相对于0的JSON数组索引:

$.track.segments[0].location

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

$.track.segments.size()

在路径表达式中使用jsonpath操作符和方法的更多示例见下面Section 9.16.2.3

在定义路径时,还可以使用一个或多个与SQL中的WHERE子句类似的filter expressions。 过滤器表达式以问号开头,并在圆括号中提供条件:

? (condition)

过滤表达式必须在它们应该应用的路径求值步骤之后写入。该步骤的结果将被筛选,以只包括满足所提供条件的那些项。 SQL/JSON定义了三值逻辑,因此条件可以是 true, false,或 unknownunknown值发挥与SQL NULL相同的角色,可以使用is unknown谓词进行测试。 进一步的路径求值步骤只使用筛选器表达式返回true的那些项。

可以在过滤表达式中使用的函数和操作符罗列在Table 9.50中。 在一个过滤表达式中,@变量表示被过滤的值(也就是说,前面路径步骤的一个结果)。你可以在 @后面写访问操作符来检索组件项。

例如,假设你想要检索所有高于130的心率值。你可以使用下面的表达式来实现这一点:

$.track.segments[*].HR ? (@ > 130)

为了获得具有这些值的片段的开始时间,必须在返回开始时间之前过滤掉不相关的片段,所以过滤表达式应用于上一步,条件中使用的路径不同:

$.track.segments[*] ? (@.HR > 130)."start time"

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

$.track.segments[*] ? (@.location[1] < 13.4) ? (@.HR > 130)."start time"

也允许在不同嵌套层级中使用过滤器表达式。下面的示例首先根据位置筛选所有的片段,然后返回这些片段的高心率值,如果适用的话:

$.track.segments[*] ? (@.location[1] < 13.4).HR ? (@ > 130)

你也可以在彼此之间嵌套过滤器表达式:

$.track ? (exists(@.segments[*] ? (@.HR > 130))).segments.size()

如果包含任何具有高心率值的片段,则该表达式返回曲目的大小,否则返回空序列。

9.16.2.1. 与 SQL 标准的偏差 #

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

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

作为对 SQL 标准的扩展,PostgreSQL 的路径表达式可以是布尔谓词,而 SQL 标准只允许在过滤器内部使用谓词。SQL 标准路径表达式返回被查询 JSON 值中的相关元素,而谓词检查表达式返回该谓词的单个三值 jsonb 结果:truefalsenull。例如,下面是一个符合 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路径表达式有两种处理结构错误的模式:

  • 不严格的(lax)(默认)—路径引擎隐式地将查询的数据适配到指定的路径。任何剩余的结构错误都将被抑制并转换为空SQL/JSON序列。

  • 严格的(strict) —如果发生了结构错误,则会引发错误。

如果JSON数据不符合期望的模式,不严格的(lax)模式有助于匹配JSON文档结构和路径表达式。 如果操作不匹配特定操作的要求,可以自动将其包装为SQL/JSON数组,也可以在执行该操作之前将其元素转换为SQL/JSON序列来解包装。 此外,比较操作符会自动以lax模式打开它们的操作数,因此你可以开包即用的就能比较SQL/JSON数组。 大小为1的数组被认为等于它的唯一元素。只有在以下情况下才不会自动展开:

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

  • 查询的JSON数据包含嵌套的数组。在本例中,只有最外层的数组被打开,而所有内部数组保持不变。 因此,隐式展开在每个路径求值步骤中只能向下进行一级。

例如,当查询上面列出的GPS数据时,当使用不严格的(lax)模式时,你可以从它存储了一组片段的事实中抽象出来:

lax $.track.segments.location

在严格的(strict)模式中,指定的路径必须与查询的JSON文档的结构完全匹配才能返回SQL/JSON项,因此使用该路径表达式会导致错误。 要得到与不严格的(lax)模式相同的结果,你必须显式地打开segments数组:

strict $.track.segments[*].location

.**访问器在使用lax模式时可能导致令人惊讶的结果。 例如,下面的查询选择每个HR值两次:

lax $.**.HR

发生这个,是因为.**访问器会全部选择segments数组和它的每个元素。 而当使用lax模式时,.HR访问器会自动打开数组。 为了避免意外的结果,我们建议仅在严格模式下使用.**访问器。 下面的查询选择每个HR值仅一次:

strict $.**.HR

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

Table 9.49显示了jsonpath中可用的操作符和方法。 请注意,虽然一元操作符和方法可以应用于由前一个路径步骤产生的多个值,二元操作符(加法等)只能应用于单个值。

Table 9.49. 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_array('{"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 . 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

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

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函数相同的解析规则(see Section 9.8),但有三个例外。 首先,这些方法不允许不匹配的模板模式。 其次,模板字符串中只允许以下分隔符:减号、句点、solidus(斜杠)、逗号、撇号、分号、冒号和空格。 第三,模板字符串中的分隔符必须与输入字符串完全匹配。

如果需要比较不同的日期/时间类型,则应用隐式转换。 date值可以转换为timestamptimestamptz, timestamp可以转换为timestamptz, time可以转换为timetz。 但是,除了第一个转换外,其他所有转换都依赖于当前TimeZone设置,因此只能在时区感知的jsonpath函数中执行。

Table 9.50显示了适用的过滤器表达式元素。

Table 9.50. jsonpath 过滤器表达式元素

谓词/值

描述

示例

value == valueboolean

相等比较(这个,和其他比较操作符,适用于所有JSON标量值)

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

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

value != valueboolean

value <> valueboolean

不相等比较

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

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

value < valueboolean

小于比较

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

value <= valueboolean

小于或等于比较

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

value > valueboolean

大于比较

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

value >= valueboolean

大于或等于比较

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

trueboolean

JSON 常量 true

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

falseboolean

JSON 常量 false

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

nullvalue

JSON常数null(注意,与SQL不同,与null比较可以正常工作)

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

boolean && booleanboolean

布尔 AND

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字符描述的修改(参见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 stringboolean

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

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.51 中描述的 SQL/JSON 函数 JSON_EXISTS()JSON_QUERY()JSON_VALUE() 可用于查询 JSON 文档。每个这样的函数都会将 path_expression(一个 SQL/JSON 路径查询)应用到 context_item(该文档)上。关于 path_expression 可以包含哪些内容的更多细节,请参见 Section 9.16.2path_expression 还可以引用变量, 这些变量的值通过各函数所支持的 PASSING 子句,以各自的名称指定。 context_item 可以是一个 jsonb 值, 也可以是一个能够成功强制转换为 jsonb 的字符串。

Table 9.51. SQL/JSON 查询函数

函数签名

描述

示例

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

  • 如果将 SQL/JSON path_expression 应用于 context_item 后产生了任何项, 则返回 true,否则返回 false。

  • ON ERROR 子句指定在计算 path_expression 期间发生错误时的行为。 指定 ERROR 将导致抛出带有相应消息的错误。 其他选项包括返回 booleanFALSETRUE,或者返回值 UNKNOWN, 它实际上是一个 SQL NULL。在未指定 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 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 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 path_expression 应用于 context_item 的结果。

  • 只有在预期提取出的值是单个 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


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 表一样访问它。 你可以在 SELECTUPDATEDELETEFROM 子句中使用 JSON_TABLE,也可以在 MERGE 语句中将其用作数据源。

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 数据的原始表进行联接。

语法如下:

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


其中 json_table_column 为:

  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 子句来格式化输出。请注意, 如果也指定了 FORMAT JSON,那么指定 OMIT QUOTES 会覆盖它,因为不带引号的字面量 不构成合法的 json 值。

你还可以选择使用 ON EMPTYON ERROR 子句来指定: 当 JSON 路径求值结果为空时,以及当 JSON 路径求值期间发生错误, 或将 SQL/JSON 值强制转换为指定类型时发生错误时,是抛出错误还是返回指定的值。 这两者的默认行为都是返回 NULL 值。

Note

该子句在内部会被转换为 JSON_VALUEJSON_QUERY,并具有相同的语义。 如果指定的类型不是标量类型,或者出现了 FORMAT JSONWRAPPERQUOTES 子句中的任意一个,则会转换为后者。

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; 使用 EMPTY 则返回一个空表,也就是一个包含 0 行的表。 请注意,该子句不会影响计算列时发生的错误; 对于列中的错误,其行为取决于对应列上是否指定了 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
     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 实现的“兄弟联接”, 以及在 NESTED 层级上使用 FOR ORDINALITY 列(列 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)

提交更正

如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。