PostgreSQL JSON 函数和操作符
- 9.16.1. 处理和创建JSON数据
- 9.16.2. SQL/JSON 路径语言
本节描述:
-
用于处理和创建JSON数据的函数和运算器
-
SQL/JSON路径语言
要了解有关SQL/JSON标准的更多信息,请参阅[sqltr-19075-6]。有关PostgreSQL中支持的JSON类型的详细信息,见 第 8.14 节。 .
9.16.1. 处理和创建JSON数据
表 9.44展示了可以用于 JSON 数据类型(见第 8.14 节)的操作符。 此外,表 9.1所示的常用比较操作符也适用于jsonb
,但不适用于json
。 比较操作符遵循 第 8.14.4 节中的B树操作概要的排序规则。
表 9.44. json
和 jsonb
操作符
操作符 描述 例子 |
---|
提取JSON数组的第 |
用给定的键提取JSON对象字段。 |
提取JSON数组的第 |
用给定的键提取JSON对象字段,作为 |
提取指定路径下的JSON子对象,路径元素可以是字段键或数组索引。 |
将指定路径上的JSON子对象提取为 |
注意
如果JSON输入没有匹配请求的正确结构,字段/元素/路径提取操作符返回NULL,而不是失败;例如,如果不存在这样的键或数组元素。
还有一些操作符仅适用于jsonb
,如表表 9.45所示。 第第 8.14.4 节描述了如何使用这些操作符来有效地搜索索引的
jsonb
数据。
表 9.45. 附加的 jsonb
操作符
操作符 描述 例子 |
---|
第一个JSON值是否包含第二个?(请参见第 8.14.3 节以了解包含的详细信息。) |
第二个JSON中是否包含第一个JSON值? |
文本字符串是否作为JSON值中的顶级键或数组元素存在? |
文本数组中的字符串是否作为顶级键或数组元素存在? |
文本数组中的所有字符串都作为顶级键或数组元素存在吗? |
连接两个 |
从JSON对象中删除键(以及它的值),或从JSON数组中删除匹配的字符串值。 |
从左操作数中删除所有匹配的键或数组元素。 |
删除具有指定索引的数组元素(负整数从末尾计数)。如果JSON值不是数组,则抛出错误。 |
删除指定路径上的字段或数组元素,路径元素可以是字段键或数组索引。 |
JSON路径是否为指定的JSON值返回任何项? |
返回指定JSON值的JSON路径谓词检查的结果。只考虑结果的第一项。如果结果不是布尔值,则返回 |
注意
jsonpath
操作符@?
和 @@
抑制以下错误:缺少对象字段或数组元素,意外的JSON项目类型,日期时间和数字错误。 还可以告诉以下描述的与jsonpath
相关的函数来抑制这些类型的错误。在搜索不同结构的JSON文档集合时,此行为可能会有所帮助。 The jsonpath
operators
@?
and @@
suppress the following errors: missing object field or array element, unexpected JSON item type, datetime and numeric errors. The jsonpath
-related functions described below can also
be told to suppress these types of errors. This behavior might be helpful when searching JSON document collections of varying structure.
表 9.46 显示可用于构造json
和jsonb
值的函数。
表 9.46. JSON 创建函数
函数 描述 例子 |
---|
将任何SQL值转换为 |
将SQL数组转换为JSON数组。该行为与 |
将SQL组合值转换为JSON对象。该行为与 |
根据可变参数列表构建可能异构类型的JSON数组。每个参数都按照 |
根据可变参数列表构建一个JSON对象。按照惯例,参数列表由交替的键和值组成。 关键参数强制转换为文本;值参数按照 |
从文本数组构建JSON对象。该数组必须有两个维度,一个维度的成员数为偶数,在这种情况下,它们被视为交替的键/值对; 另一个维度的成员数为二维,每个内部数组恰好有两个元素,它们被视为键/值对。所有值都转换为JSON字符串。
|
这种形式的 |
[a]
例如,hstore扩展有一个从 |
表 9.47 显示可用于处理json
和jsonb
值的函数。
表 9.47. JSON 处理函数
函数 描述 例子 |
---|
将顶级JSON数组展开为一组JSON值。
|
将顶级JSON数组展开为一组
|
返回顶级JSON数组中的元素数量。 |
将顶级JSON对象展开为一组键/值对。
|
将顶级JSON对象扩展为一组键/值对。返回的
|
在指定路径下提取JSON子对象。(这在功能上相当于 |
将指定路径上的JSON子对象提取为 |
返回顶级JSON对象中的键集合。
|
将顶级JSON对象扩展为具有 要将JSON值转换为输出列的SQL类型,需要按次序应用以下规则:
虽然下面的示例使用一个常量JSON值,典型的用法是在查询的
|
将对象的顶级JSON数组展开为一组具有
|
将顶级JSON对象展开为具有由
|
将顶级JSON对象数组展开为一组由
|
返回 |
如果 |
返回插入 |
从给定的JSON值中删除所有具有空值的对象字段,递归地。非对象字段的空值是未受影响的。 |
检查JSON路径是否返回指定JSON值的任何项。如果指定了 |
返回指定JSON值的JSON路径谓词检查的结果。只有结果的第一项被考虑在内。 如果结果不是布尔值,则返回 |
为指定的JSON值返回由JSON路径返回的所有JSON项。可选的
|
以JSON数组的形式返回由JSON路径为指定的JSON值返回的所有JSON项。可选的 |
为指定的JSON值返回由JSON路径返回的第一个JSON项。如果没有结果则返回 |
这些函数与上面描述的没有 |
将给定的JSON值转换为精美打印的,缩进的文本。
|
以文本字符串形式返回顶级JSON值的类型。可能的类型有 |
参见 第 9.21 节,聚合函数json_agg
将聚合记录值为JSON,聚合函数json_object_agg
将聚合成对的值为JSON对象, 以及它们在jsonb
中的相当的(函数),
jsonb_agg
和jsonb_object_agg
。
9.16.2. SQL/JSON 路径语言
SQL/JSON路径表达式指定了要从JSON数据中检索的项目,类似于SQL访问XML时使用的XPath表达式。 在PostgreSQL中,路径表达式作为jsonpath
数据类型实现,可以使用第 8.14.6 节中描述的任何元素。
JSON查询函数和操作符将提供的路径表达式传递给path engine进行评估。 如果表达式与被查询的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
}
]
}
}
为了检索可用的轨迹段,你需要使用.
访问操作符来向下浏览周边的JSON对象:key
$.track.segments
要检索数组的内容,通常使用[*]
操作符。例如,下面的路径将返回所有可用轨道段的位置坐标:
$.track.segments[*].location
要只返回第一个段的坐标,可以在[]
访问操作符中指定相应的下标。重新调用相对于0的JSON数组索引:
$.track.segments[0].location
每个路径求值步骤的结果可以由本文中第 9.16.2.2 节中列出的一个或多个jsonpath
操作符和方法来处理。 每个方法名之前必须有一个点。例如,你可以得到一个数组的大小:
$.track.segments.size()
在路径表达式中使用jsonpath
操作符和方法的更多示例见下面本文中第 9.16.2.2 节。
在定义路径时,还可以使用一个或多个与SQL中的WHERE
子句类似的filter expressions。 过滤器表达式以问号开头,并在圆括号中提供条件:
? (condition
)
过滤表达式必须在它们应该应用的路径求值步骤之后写入。该步骤的结果将被筛选,以只包括满足所提供条件的那些项。 SQL/JSON定义了三值逻辑,因此条件可以是 true
, false
,或 unknown
。 unknown
值发挥与SQL NULL
相同的角色,可以使用
is unknown
谓词进行测试。 进一步的路径求值步骤只使用筛选器表达式返回true
的那些项。
可以在过滤表达式中使用的函数和操作符罗列在表 9.49中。 在一个过滤表达式中,@
变量表示被过滤的值(也就是说,前面路径步骤的一个结果)。你可以在 @
后面写访问操作符来检索组件项。
例如,假设你想要检索所有高于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()
如果包含任何具有高心率值的片段,则该表达式返回曲目的大小,否则返回空序列。
PostgreSQL的SQL/JSON路径语言的实现与SQL/JSON标准有以下偏差:
-
路径表达式可以是布尔谓词,尽管SQL/JSON标准只允许在过滤器中使用谓词。 这是实现
@@
操作符所必需的。例如,下面的jsonpath
表达式在PostgreSQL中是有效的:$.track.segments[*].HR < 70
-
在解释
like_regex
过滤器中使用的正则表达式模式方面有一些小的差异,如本文中第 9.16.2.3 节中所述。
9.16.2.1. 严格的(Strict) 和 不严格的(Lax) 模式
当查询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
9.16.2.2. SQL/JSON 路径操作符和方法
表 9.48显示了jsonpath中可用的操作符和方法。 请注意,虽然一元操作符和方法可以应用于由前一个路径步骤产生的多个值,二元操作符(加法等)只能应用于单个值。
表 9.48. jsonpath
操作符和方法
操作符/方法 描述 例子 |
---|
加法 |
一元加号(无操作);与加法不同,这个可以迭代多个值 |
减法 |
否定;与减法不同,它可以迭代多个值 |
乘法 |
除法 |
模数 (余数) |
JSON项的类型 (参见 |
JSON项的大小(数组元素的数量,如果不是数组则为1) |
从JSON数字或字符串转换过来的近似浮点数 |
大于或等于给定数字的最接近的整数 |
小于或等于给定数字的最近整数 |
给定数字的绝对值 |
从字符串转换过来的日期/时间值 |
使用指定的 |
对象的键值对,表示为包含三个字段的对象数组: |
注意
datetime()
和datetime(
方法的结果类型可以是template
)date
, timetz
, time
,timestamptz
, 或 timestamp
。 这两个方法都动态地确定它们的结果类型。
datetime()
方法依次尝试将其输入字符串与date
, timetz
, time
,timestamptz
, 和 timestamp
的ISO格式进行匹配。 它在第一个匹配格式时停止,并发出相应的数据类型。
datetime(
方法根据所提供的模板字符串中使用的字段确定结果类型。template
)
datetime()
和datetime(
方法使用与template
)to_timestamp
SQL函数相同的解析规则(see 第 9.8 节),但有三个例外。 首先,这些方法不允许不匹配的模板模式。 其次,模板字符串中只允许以下分隔符:减号、句点、solidus(斜杠)、逗号、撇号、分号、冒号和空格。
第三,模板字符串中的分隔符必须与输入字符串完全匹配。
如果需要比较不同的日期/时间类型,则应用隐式转换。 date
值可以转换为timestamp
或 timestamptz
, timestamp
可以转换为timestamptz
, time
可以转换为
timetz
。 但是,除了第一个转换外,其他所有转换都依赖于当前TimeZone设置,因此只能在时区感知的jsonpath
函数中执行。
表 9.49显示了适用的过滤器表达式元素。
表 9.49. jsonpath
过滤器表达式元素
谓词/值 描述 例子 |
---|
相等比较(这个,和其他比较操作符,适用于所有JSON标量值) |
不相等比较 |
小于比较 |
小于或等于比较 |
大于比较 |
大于或等于比较 |
JSON常数 |
JSON常数 |
JSON常数 |
布尔 AND |
布尔 OR |
布尔 NOT |
测试布尔条件是否为 |
测试第一个操作数是否与第二个操作数给出的正则表达式匹配,可选使用由一串 |
测试第二个操作数是否为第一个操作数的初始子串。 |
测试路径表达式是否至少匹配一个SQL/JSON项。 如果路径表达式会导致错误,则返回 |
9.16.2.3. 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
过滤器是使用第 9.7.3 节中描述的POSIX正则表达式引擎来实现的。 这导致了与标准SQL/JSON行为的各种细微差异,这在第 9.7.3.8 节中进行了分类。 但是请注意,这里描述的标志字母不兼容并不适用于SQL/JSON,因为它将XQuery标志字母翻译为符合POSIX引擎的预期。
请记住,like_regex
的模式参数是一个JSON路径字符串文字,根据第 8.14.6 节给出的规则编写。 这特别意味着在正则表达式中要使用的任何反斜杠都必须加倍。例如,匹配只包含数字的字符串:
$ ? (@ like_regex "^\\d+$")