本节介绍
用于处理和创建 JSON 数据的函数和操作符
SQL/JSON 路径语言
SQL/JSON 查询函数
为了在 SQL 环境中提供对 JSON 数据类型的原生支持,PostgreSQL 实现了SQL/JSON 数据模型。此模型包含一系列项。每一项可以包含 SQL 标量值、一个额外的 SQL/JSON 空值,以及使用 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.45 显示了可用于 JSON 数据类型的操作符(请参阅 第 8.14 节)。此外,表 9.1 中显示的常用比较运算符可用于 jsonb
,但不能用于 json
。比较运算符遵循 第 8.14.4 节中概述的 B 树操作的排序规则。另请参阅 第 9.21 节,了解将记录值聚合为 JSON 的聚合函数 json_agg
,将值对聚合为 JSON 对象的聚合函数 json_object_agg
,以及它们的 jsonb
等效函数 jsonb_agg
和 jsonb_object_agg
。
表 9.45. json
和 jsonb
操作符
操作符 描述 示例 |
---|
提取 JSON 数组的第
|
提取具有给定键的 JSON 对象字段。
|
提取 JSON 数组的第
|
提取具有给定键的 JSON 对象字段,作为
|
提取指定路径上的 JSON 子对象,其中路径元素可以是字段键或数组索引。
|
提取指定路径上的 JSON 子对象,作为
|
如果 JSON 输入没有正确的结构来匹配请求,例如如果不存在这样的键或数组元素,则字段/元素/路径提取操作符将返回 NULL,而不是失败。
某些其他操作符仅适用于 jsonb
,如表 9.46所示。第 8.14.4 节描述了如何使用这些操作符有效地搜索索引的 jsonb
数据。
表 9.46. 其他 jsonb
操作符
操作符 描述 示例 |
---|
第一个 JSON 值是否包含第二个?(有关包含的详细信息,请参阅 第 8.14.3 节。)
|
第一个 JSON 值是否包含在第二个中?
|
文本字符串是否存在于 JSON 值中的顶级键或数组元素?
|
文本数组中的任何字符串是否存在为顶级键或数组元素?
|
文本数组中的所有字符串是否存在为顶级键或数组元素?
|
连接两个
要将数组作为单个条目附加到另一个数组,请将其包裹在额外的数组层中,例如:
|
从 JSON 对象中删除键(及其值),或从 JSON 数组中删除匹配的字符串值。
|
从左操作数中删除所有匹配的键或数组元素。
|
删除具有指定索引的数组元素(负整数从末尾开始计数)。如果 JSON 值不是数组,则会引发错误。
|
删除指定路径上的字段或数组元素,其中路径元素可以是字段键或数组索引。
|
指定的 JSON 值是否返回 JSON 路径中的任何项? (这仅对 SQL 标准的 JSON 路径表达式有用,不适用于谓词检查表达式,因为谓词检查表达式总是返回值。)
|
返回指定 JSON 值的 JSON 路径谓词检查的结果。(这仅对谓词检查表达式有用,不适用于 SQL 标准的 JSON 路径表达式,因为如果路径结果不是单个布尔值,它将返回
|
jsonpath
运算符 @?
和 @@
会抑制以下错误:缺少对象字段或数组元素、意外的 JSON 项类型、日期时间错误和数字错误。下文描述的 jsonpath
相关函数也可以被告知抑制这些类型的错误。当搜索结构各异的 JSON 文档集合时,此行为可能会很有用。
表 9.47 显示了可用于构造 json
和 jsonb
值的函数。此表中的某些函数具有 RETURNING
子句,该子句指定返回的数据类型。它必须是 json
、jsonb
、bytea
、字符字符串类型(text
、char
或 varchar
)或可以强制转换为 json
的类型。默认情况下,返回 json
类型。
表 9.47. JSON 创建函数
函数 描述 示例 |
---|
将任何 SQL 值转换为
|
将 SQL 数组转换为 JSON 数组。行为与
|
从一系列
|
将 SQL 复合值转换为 JSON 对象。行为与
|
从可变参数列表构建可能具有异构类型的 JSON 数组。每个参数都按照
|
从可变参数列表构建 JSON 对象。按照惯例,参数列表由交替的键和值组成。键参数被强制转换为文本;值参数按照
|
构造给定所有键/值对的 JSON 对象,如果未给出任何键/值对,则构造空对象。
|
从文本数组构建 JSON 对象。该数组必须具有以下两种情况之一:恰好一个维度,并且具有偶数个成员,在这种情况下,它们被视为交替的键/值对;或者两个维度,这样每个内部数组恰好有两个元素,这些元素被视为键/值对。所有值都转换为 JSON 字符串。
|
此形式的
|
将指定为
|
将给定的 SQL 标量值转换为 JSON 标量值。如果输入为 NULL,则返回SQLnull。如果输入是数字或布尔值,则返回相应的 JSON 数字或布尔值。对于任何其他值,则返回 JSON 字符串。
|
将 SQL/JSON 表达式转换为字符或二进制字符串。
|
表 9.48 详细介绍了用于测试 JSON 的 SQL/JSON 功能。
表 9.48. SQL/JSON 测试函数
表 9.49 显示了可用于处理 json
和 jsonb
值的函数。
表 9.49. 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_object_keys ------------------ f1 f2 |
将顶层 JSON 对象展开为具有 要将 JSON 值转换为输出列的 SQL 类型,将按顺序应用以下规则
虽然下面的示例使用常量 JSON 值,但典型的用法是从查询的
a | b | c ---+-----------+------------- 1 | {2,"a b"} | (4,"a b c") |
用于测试
jsonb_populate_record_valid ----------------------------- f (1 row)
ERROR: value too long for type character(2)
jsonb_populate_record_valid ----------------------------- t (1 row)
a ---- aa (1 row) |
将顶级的 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 值的对象字段。不是对象字段的 Null 值保持不变。
|
检查 JSON 路径是否为指定的 JSON 值返回任何项。(这仅适用于 SQL 标准的 JSON 路径表达式,不适用于谓词检查表达式,因为这些表达式始终返回一个值。)如果指定了
|
返回指定 JSON 值的 JSON 路径谓词检查的结果。(这仅适用于谓词检查表达式,不适用于 SQL 标准 JSON 路径表达式,因为如果路径结果不是单个布尔值,它将失败或返回
|
返回 JSON 路径为指定 JSON 值返回的所有 JSON 项。对于 SQL 标准的 JSON 路径表达式,它返回从
jsonb_path_query ------------------ 2 3 4 |
将 JSON 路径为指定 JSON 值返回的所有 JSON 项作为 JSON 数组返回。参数与
|
返回指定 JSON 值的 JSON 路径返回的第一个 JSON 项,如果没有结果则返回
|
这些函数的作用类似于上面描述的没有
|
将给定的 JSON 值转换为格式化输出的、缩进的文本。
[ { "f1": 1, "f2": null }, 2 ] |
以文本字符串形式返回顶层 JSON 值的类型。可能的类型包括
|
SQL/JSON 路径表达式指定要从 JSON 值中检索的项,类似于用于访问 XML 内容的 XPath 表达式。在 PostgreSQL 中,路径表达式实现为 jsonpath
数据类型,并且可以使用 第 8.14.7 节 中描述的任何元素。
JSON 查询函数和运算符将提供的路径表达式传递给路径引擎进行计算。如果表达式与查询的 JSON 数据匹配,则返回相应的 JSON 项或项集。如果没有匹配项,则结果将为 NULL
、false
或错误,具体取决于函数。路径表达式以 SQL/JSON 路径语言编写,并且可以包含算术表达式和函数。
路径表达式由 jsonpath
数据类型允许的元素序列组成。路径表达式通常从左到右计算,但可以使用括号更改运算顺序。如果计算成功,则会生成 JSON 项序列,并且将计算结果返回给完成指定计算的 JSON 查询函数。
要引用正在查询的 JSON 值(上下文项),请在路径表达式中使用 $
变量。路径的第一个元素必须始终为 $
。它可以后跟一个或多个 访问器运算符,这些运算符逐层下降 JSON 结构以检索上下文项的子项。每个访问器运算符都会作用于前一步评估的结果,从每个输入项生成零个、一个或多个输出项。
例如,假设您有一些来自 GPS 跟踪器的 JSON 数据,您想解析这些数据,例如
SELECT '{ "track": { "segments": [ { "location": [ 47.763, 13.4034 ], "start time": "2018-10-14 10:05:14", "HR": 73 }, { "location": [ 47.706, 13.2635 ], "start time": "2018-10-14 10:39:21", "HR": 135 } ] } }' AS json \gset
(上面的示例可以复制并粘贴到 psql 中,为以下示例进行设置。然后,psql 将把 :'json'
展开为一个适当带引号的字符串常量,其中包含 JSON 值。)
要检索可用的轨迹段,您需要使用 .
访问器运算符来遍历周围的 JSON 对象,例如key
=>
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
在路径表达式中使用 jsonpath
运算符和方法的更多示例将在下面的 第 9.16.2.3 节 中出现。
路径还可以包含筛选表达式,其工作方式类似于 SQL 中的 WHERE
子句。筛选表达式以问号开头,并在括号中提供条件
? (condition
)
筛选表达式必须在它们应适用的路径评估步骤之后编写。该步骤的结果将被筛选,仅包含满足所提供条件的项。SQL/JSON 定义了三值逻辑,因此条件可以产生 true
、false
或 unknown
。unknown
值的作用与 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"
如果需要,可以按顺序使用多个筛选表达式。以下示例选择包含相关坐标和高心率值的所有段的开始时间
=>
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
PostgreSQL 的 SQL/JSON 路径语言实现与 SQL/JSON 标准有以下偏差。
作为 SQL 标准的扩展,PostgreSQL 路径表达式可以是一个布尔谓词,而 SQL 标准只允许在过滤器中使用谓词。SQL 标准的路径表达式返回所查询 JSON 值的相关元素,而谓词检查表达式返回谓词的单个三值结果:true
、false
或 unknown
。例如,我们可以编写这个 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
过滤器中使用的正则表达式模式的解释存在细微差异,如第 9.16.2.4 节所述。
当您查询 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.50 显示了 jsonpath
中可用的运算符和方法。请注意,虽然一元运算符和方法可以应用于先前路径步骤产生的多个值,但二元运算符(加法等)只能应用于单个值。在宽松模式下,应用于数组的方法将为数组中的每个值执行。例外情况是 .type()
和 .size()
,它们应用于数组本身。
表 9.50. jsonpath
运算符和方法
运算符/方法 描述 示例 |
---|
加法
|
一元加(无操作);与加法不同,它可以迭代多个值
|
减法
|
取负;与减法不同,它可以迭代多个值
|
乘法
|
除法
|
取模(余数)
|
JSON 项的类型(参见
|
JSON 项的大小(数组元素的数量,如果不是数组则为 1)
|
从 JSON 布尔值、数字或字符串转换而来的布尔值
|
从 JSON 布尔值、数字、字符串或日期时间转换而来的字符串值
|
从 JSON 数字或字符串转换而来的近似浮点数
|
大于或等于给定数字的最近整数
|
小于或等于给定数字的最近整数
|
给定数字的绝对值
|
从 JSON 数字或字符串转换而来的大整数值
|
从 JSON 数字或字符串转换而来的四舍五入的十进制值(
|
从 JSON 数字或字符串转换而来的整数值
|
从 JSON 数字或字符串转换而来的数值
|
从字符串转换而来的日期/时间值
|
使用指定的
|
从字符串转换而来的日期值
|
从字符串转换而来的不带时区的时间值
|
从字符串转换而来的不带时区的时间值,小数秒调整为给定的精度
|
从字符串转换而来的带时区的时间值
|
从字符串转换而来的带时区的时间值,小数秒调整为给定的精度
|
从字符串转换而来的不带时区的时间戳值
|
从字符串转换而来的不带时区的时间戳值,小数秒调整为给定的精度
|
从字符串转换而来的带时区的时间戳值
|
从字符串转换而来的带时区的时间戳值,小数秒调整为给定的精度
|
对象的键值对,表示为包含三个字段的对象数组:
|
datetime()
和 datetime(
方法的结果类型可以是 template
)date
、timetz
、time
、timestamptz
或 timestamp
。 这两个方法都会动态确定其结果类型。
datetime()
方法会按顺序尝试将其输入字符串与 date
、timetz
、time
、timestamptz
和 timestamp
的 ISO 格式匹配。它会在第一个匹配的格式上停止,并发出相应的数据类型。
datetime(
方法根据提供的模板字符串中使用的字段确定结果类型。template
)
datetime()
和 datetime(
方法使用与 template
)to_timestamp
SQL 函数相同的解析规则(请参阅 第 9.8 节),但有三个例外。首先,这些方法不允许不匹配的模板模式。其次,模板字符串中只允许以下分隔符:减号、句点、斜杠、逗号、单引号、分号、冒号和空格。第三,模板字符串中的分隔符必须与输入字符串完全匹配。
如果需要比较不同的日期/时间类型,则会应用隐式转换。date
值可以转换为 timestamp
或 timestamptz
,timestamp
可以转换为 timestamptz
,time
可以转换为 timetz
。但是,除了第一个转换外,所有这些转换都依赖于当前的 TimeZone 设置,因此只能在时区感知的 jsonpath
函数中执行。类似地,其他将字符串转换为日期/时间类型的日期/时间相关方法也会执行此转换,这可能涉及到当前的 TimeZone 设置。因此,这些转换也只能在时区感知的 jsonpath
函数中执行。
表 9.51 显示了可用的过滤器表达式元素。
表 9.51. 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
运算符借用其正则表达式的定义,而 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.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 查询函数
函数签名 描述 示例 |
---|
示例
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
子句进行处理。
JSON_VALUE()
函数如果 path_expression
返回 JSON null
,则返回 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 值,该值将成为给定输出行中指定列的值。
可以使用 NESTED PATH
子句提取存储在行模式嵌套级别的 JSON 数据。每个 NESTED PATH
子句都可以用于使用行模式嵌套级别的数据生成一个或多个列。这些列可以使用与顶级 COLUMNS 子句类似的 COLUMNS
子句指定。从 NESTED COLUMNS 构建的行称为子行,并与从父 COLUMNS
子句中指定的列构造的行进行连接,以获取最终视图中的行。子列本身可能包含 NESTED PATH
规范,从而允许提取位于任意嵌套级别的数据。在同一级别由多个 NESTED PATH
生成的列被认为是彼此的兄弟姐妹,它们在与父行连接后的行使用 UNION 进行组合。
JSON_TABLE
生成的行与生成它们的行进行横向连接,因此您不必显式将构造的视图与持有原始数据的表进行连接。JSON数据。
语法如下:
JSON_TABLE (context_item
,path_expression
[ ASjson_path_name
] [ PASSING {value
ASvarname
} [, ...] ] COLUMNS (json_table_column
[, ...] ) [ {ERROR
|EMPTY
[ARRAY]}ON ERROR
] ) wherejson_table_column
is:name
FOR ORDINALITY |name
type
[ FORMAT JSON [ENCODINGUTF8
]] [ PATHpath_expression
] [ { WITHOUT | WITH { CONDITIONAL | [UNCONDITIONAL] } } [ ARRAY ] WRAPPER ] [ { KEEP | OMIT } QUOTES [ ON SCALAR STRING ] ] [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULTexpression
} ON EMPTY ] [ { ERROR | NULL | EMPTY { [ARRAY] | OBJECT } | DEFAULTexpression
} ON ERROR ] |name
type
EXISTS [ PATHpath_expression
] [ { ERROR | TRUE | FALSE | UNKNOWN } ON ERROR ] | NESTED [ PATH ]path_expression
[ ASjson_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
子句定义构造视图的模式。在此子句中,您可以指定每一列都填充一个 SQL/JSON 值,该值是通过对行模式应用 JSON 路径表达式获得的。json_table_column
具有以下变体
name
FOR ORDINALITY
添加一个序号列,该列提供从 1 开始的顺序行编号。每个 NESTED PATH
(见下文)都会为其任何嵌套的序号列获取自己的计数器。
name
type
[FORMAT JSON
[ENCODING UTF8
]] [ PATH
path_expression
]
在将行模式强制转换为指定的 type
后,将通过对行模式应用 path_expression
获得的 SQL/JSON 值插入到视图的输出行中。
指定 FORMAT JSON
可以明确表示您期望该值为有效的 json
对象。只有当 type
是 bpchar
、bytea
、character varying
、name
、json
、jsonb
、text
或这些类型的域之一时,指定 FORMAT JSON
才是有意义的。
可选地,您可以指定 WRAPPER
和 QUOTES
子句来格式化输出。请注意,如果还指定了 OMIT QUOTES
,它会覆盖 FORMAT JSON
,因为未加引号的文字不构成有效的 json
值。
可选地,您可以使用 ON EMPTY
和 ON ERROR
子句来指定当 JSON 路径评估结果为空时以及当 JSON 路径评估期间发生错误或将 SQL/JSON 值强制转换为指定类型时,是抛出错误还是返回指定值。两者的默认值都是返回 NULL
值。
此子句在内部转换为,并且具有与 JSON_VALUE
或 JSON_QUERY
相同的语义。如果指定类型不是标量类型,或者如果存在 FORMAT JSON
、WRAPPER
或 QUOTES
子句,则后者。
name
type
EXISTS
[ PATH
path_expression
]在将行模式强制转换为指定的 type
后,将通过对行模式应用 path_expression
获得的布尔值插入到视图的输出行中。
该值对应于对行模式应用 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_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, '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
来填充标题和导演列,说明它们如何连接到父列 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)
如果您在文档中看到任何不正确、与您使用特定功能的经验不符或需要进一步澄清的内容,请使用此表单报告文档问题。