本节描述:
用于处理和创建 JSON 数据的函数和操作符
SQL/JSON路径语言
要了解有关SQL/JSON标准的更多信息,请参阅[sqltr-19075-6]。有关PostgreSQL中支持的JSON类型的详细信息,见 Section 8.14。
Table 9.47显示了可用于 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_agg和jsonb_object_agg。
Table 9.47. json 和 jsonb 操作符
|
操作符 描述 示例 |
|---|
|
提取JSON数组的第
|
|
用给定的键提取JSON对象字段。
|
|
提取JSON数组的第
|
|
用给定的键提取JSON对象字段,作为
|
|
提取指定路径下的JSON子对象,路径元素可以是字段键或数组索引。
|
|
将指定路径上的JSON子对象提取为
|
如果 JSON 输入没有匹配请求的正确结构,字段/元素/路径提取操作符会返回 NULL,而不是失败;例如,如果不存在这样的键或数组元素。
还有一些操作符仅适用于jsonb,如表Table 9.48所示。 第Section 8.14.4描述了如何使用这些操作符来有效地搜索索引的jsonb数据。
Table 9.48. 附加的 jsonb 操作符
|
操作符 描述 示例 |
|---|
|
第一个JSON值是否包含第二个?(请参见Section 8.14.3以了解包含的详细信息。)
|
|
第二个JSON中是否包含第一个JSON值?
|
|
文本字符串是否作为JSON值中的顶级键或数组元素存在?
|
|
文本数组中的字符串是否作为顶级键或数组元素存在?
|
|
文本数组中的所有字符串都作为顶级键或数组元素存在吗?
|
|
连接两个
要将一个数组作为单个条目附加到另一个数组中,请将其包装在另一个数组附加层中,例如:
|
|
从JSON对象中删除键(以及它的值),或从JSON数组中删除匹配的字符串值。
|
|
从左操作数中删除所有匹配的键或数组元素。
|
|
删除具有指定索引的数组元素(负整数从末尾计数)。如果JSON值不是数组,则抛出错误。
|
|
删除指定路径上的字段或数组元素,路径元素可以是字段键或数组索引。
|
|
JSON路径是否为指定的JSON值返回任何项?
|
|
返回指定JSON值的JSON路径谓词检查的结果。只考虑结果的第一项。如果结果不是布尔值,则返回
|
jsonpath操作符@? 和 @@会抑制以下错误:缺少对象字段或数组元素、意外的 JSON 项目类型,以及日期时间和数字错误。 还可以告诉以下描述的与jsonpath相关的函数来抑制这些类型的错误。 在搜索不同结构的JSON文档集合时,此行为可能会有所帮助。
Table 9.49 显示可用于构造json和jsonb值的函数。
Table 9.49. JSON 创建函数
|
函数 描述 示例 |
|---|
|
将任何SQL值转换为
|
|
将SQL数组转换为JSON数组。该行为与
|
|
将SQL组合值转换为JSON对象。该行为与
|
|
根据可变参数列表构建可能异构类型的JSON数组。每个参数都按照
|
|
根据可变参数列表构建一个JSON对象。按照惯例,参数列表由交替的键和值组成。 键参数会被强制转换为文本;值参数则按照
|
|
从文本数组构建JSON对象。该数组必须有两个维度,一个维度的成员数为偶数,在这种情况下,它们被视为交替的键/值对; 另一个维度的成员数为二维,每个内部数组恰好有两个元素,它们被视为键/值对。所有值都转换为JSON字符串。
|
|
这种形式的
|
Table 9.50 显示可用于处理json和jsonb值的函数。
Table 9.50. JSON 处理函数
|
函数 描述 示例 |
|---|
|
将顶级JSON数组展开为一组JSON值。
value ----------- 1 true [2,false] |
|
将顶级 JSON 数组展开为一组
value ----------- foo bar |
|
返回顶层JSON数组中的元素数量。
|
|
将顶级JSON对象展开为一组键/值对。
key | value -----+------- a | "foo" b | "bar" |
|
将顶级 JSON 对象展开为一组键/值对。返回的
key | value -----+------- a | foo b | bar |
|
在指定路径下提取JSON子对象。(这在功能上相当于
|
|
将指定路径上的 JSON 子对象提取为
|
|
返回顶级JSON对象中的键集合。
json_object_keys ------------------ f1 f2 |
|
将顶级 JSON 对象展开为具有 要将JSON值转换为输出列的SQL类型,需要按次序应用以下规则:
虽然下面的示例使用一个常量JSON值,典型的用法是在查询的
a | b | c
---+-----------+-------------
1 | {2,"a b"} | (4,"a b c")
|
|
将对象的顶级 JSON 数组展开为一组具有
a | b ---+--- 1 | 2 3 | 4 |
|
将顶级JSON对象展开为具有由
a | b | c | d | r
---+---------+---------+---+---------------
1 | [1,2,3] | {1,2,3} | | (123,"a b c")
|
|
将顶级JSON对象数组展开为一组由
a | b ---+----- 1 | foo 2 | |
|
返回
|
|
如果
|
|
返回插入
|
|
递归地删除给定 JSON 值中所有值为 null 的对象字段。如果
|
|
检查JSON路径是否返回指定JSON值的任何项。如果指定了
|
|
返回指定JSON值的JSON路径谓词检查的结果。只有结果的第一项被考虑在内。 如果结果不是布尔值,则返回
|
|
为指定的JSON值返回由JSON路径返回的所有JSON项。可选的
jsonb_path_query ------------------ 2 3 4 |
|
以JSON数组的形式返回由JSON路径为指定的JSON值返回的所有JSON项。可选的
|
|
为指定的JSON值返回由JSON路径返回的第一个JSON项。如果没有结果则返回
|
|
这些函数的作用类似于上面描述的没有
|
|
将给定的JSON值转换为精美打印的,缩进的文本。
[
{
"f1": 1,
"f2": null
},
2
]
|
|
以文本字符串形式返回顶级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
}
]
}
}
为了检索可用的轨迹段,你需要使用.访问操作符来向下浏览周边的JSON对象:key
$.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,或 unknown。 unknown值发挥与SQL NULL相同的角色,可以使用is unknown谓词进行测试。 进一步的路径求值步骤只使用筛选器表达式返回true的那些项。
可以在过滤表达式中使用的函数和操作符罗列在Table 9.52中。 在一个过滤表达式中,@变量表示被过滤的值(也就是说,前面路径步骤的一个结果)。你可以在 @后面写访问操作符来检索组件项。
例如,假设你想要检索所有高于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 标准的扩展,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
谓词检查表达式是 @@ 操作符(以及 jsonb_path_match 函数)所必需的,不应与 @? 操作符(或 jsonb_path_exists 函数)一起使用。
对于 like_regex 过滤器中使用的正则表达式模式,其解释方式存在一些细微差异,详见Section 9.16.2.4。
当查询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
Table 9.51显示了jsonpath中可用的操作符和方法。 请注意,虽然一元操作符和方法可以应用于由前一个路径步骤产生的多个值,二元操作符(加法等)只能应用于单个值。
Table 9.51. 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 Section 9.8),但有三个例外。 首先,这些方法不允许不匹配的模板模式。 其次,模板字符串中只允许以下分隔符:减号、句点、solidus(斜杠)、逗号、撇号、分号、冒号和空格。 第三,模板字符串中的分隔符必须与输入字符串完全匹配。
如果需要比较不同的日期/时间类型,则应用隐式转换。 date值可以转换为timestamp或 timestamptz, timestamp可以转换为timestamptz, time可以转换为timetz。 但是,除了第一个转换外,其他所有转换都依赖于当前TimeZone设置,因此只能在时区感知的jsonpath函数中执行。
Table 9.52显示了适用的过滤器表达式元素。
Table 9.52. jsonpath 过滤器表达式元素
|
谓词/值 描述 示例 |
|---|
|
相等比较(这个,和其他比较操作符,适用于所有JSON标量值)
|
|
不相等比较
|
|
小于比较
|
|
小于或等于比较
|
|
大于比较
|
|
大于或等于比较
|
|
JSON 常量
|
|
JSON 常量
|
|
JSON常数
|
|
布尔 AND
|
|
布尔 OR
|
|
布尔 NOT
|
|
测试布尔条件是否为
|
|
测试第一个操作数是否与第二个操作数给出的正则表达式匹配,可选使用由一串
|
|
测试第二个操作数是否为第一个操作数的初始子串。
|
|
测试路径表达式是否至少匹配一个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+$")
Table 9.53 中描述的 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.53. SQL/JSON 查询函数
|
函数签名 描述 示例 |
|---|
示例:
ERROR: jsonpath array subscript is out of bounds |
示例:
ERROR: malformed array literal: "[1, 2]" DETAIL: Missing "]" after array dimensions. |
示例:
|
如果 context_item 表达式的类型还不是 jsonb,则会通过隐式强制转换将其转换为 jsonb。 但请注意,在该转换期间发生的任何解析错误都会无条件抛出, 也就是说,不会按照(显式指定或隐含的)ON ERROR 子句来处理。
如果 path_expression 返回 JSON null,则 JSON_VALUE() 返回 SQL NULL, 而 JSON_QUERY() 则按原样返回 JSON null。
JSON_TABLE 是一个 SQL/JSON 函数, 用于查询 JSON 数据, 并将结果表示为关系视图,从而可以像访问常规 SQL 表一样访问它。 你可以在 SELECT、UPDATE 或 DELETE 的 FROM 子句中使用 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_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 子句来格式化输出。请注意, 如果也指定了 FORMAT JSON,那么指定 OMIT QUOTES 会覆盖它,因为不带引号的字面量 不构成合法的 json 值。
你还可以选择使用 ON EMPTY 和 ON ERROR 子句来指定: 当 JSON 路径求值结果为空时,以及当 JSON 路径求值期间发生错误, 或将 SQL/JSON 值强制转换为指定类型时发生错误时,是抛出错误还是返回指定的值。 这两者的默认行为都是返回 NULL 值。
该子句在内部会被转换为 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。
该子句在内部会被转换为 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 子句,则使用路径表达式 $.,其中 namename 是提供的列名。
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_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 实现的“兄弟联接”, 以及在 NESTED 层级上使用 FOR ORDINALITY 列(列 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)
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。