本节介绍
用于处理和创建 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.45 显示了可用于 JSON 数据类型的运算符(请参见 8.14 节)。此外,表 9.1 中显示的常规比较运算符可用于 jsonb
,但不可用于 json
。比较运算符遵循 8.14.4 节 中概述的 B 树操作排序规则。另请参阅 9.21 节,了解如下内容:聚合函数 json_agg
(将记录值聚合为 JSON)、聚合函数 json_object_agg
(将值对聚合为 JSON 对象),以及它们对应的 jsonb
等效项 jsonb_agg
和 jsonb_object_agg
。
表 9.45. json
和 jsonb
运算符
运算符 说明 示例 |
---|
提取 JSON 数组的第
|
提取具有给定键的 JSON 对象字段。
|
提取 JSON 数组的第
|
作为
|
提取指定路径处的 JSON 子对象,其中路径元素可以是字段键数组或索引。
|
作为
|
如果 JSON 输入没有匹配请求的正确结构,字段/元素/路径提取运算符将返回 NULL 而不是失败;例如,如果不存在这样的键或数组元素。
某些其他运算符只存在于 jsonb
中,如 表 9.46 所示。 章节 8.14.4 描述了如何使用这些运算符有效搜索索引 jsonb
数据。
表 9.46。其他 jsonb
运算符
运算符 说明 示例 |
---|
第一个 JSON 值是否包含第二个 JSON 值?(有关包含的详细信息,请参见章节 8.14.3。)
|
第一个 JSON 值是否包含在第二个 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 数组。如果可选布尔参数为 true,则行为与
|
从一系列
|
将 SQL 复合值转换为 JSON 对象。如果可选布尔参数为 true,则行为与
|
将一个可变参数列表构建为一个可能类型不同的 JSON 数组。每个参数会按照
|
将一个可变参数列表构建为一个 JSON 对象。按照惯例,参数列表包含交替出现的键和值。键参数强制转换为文本;值参数按照
|
用给定的所有键/值对来构造一个 JSON 对象,如果未给出任何值,则为一个空对象。
|
从文本数组中构建 JSON 对象。数组必须具有恰好一个维度和偶数个成员,这种情况下,以它们作为交替的键值对;或者具有两个维度,使得每个内部数组恰好有 2 个元素,它们被视为键值对。所有值都转换 JSON 字符串。
|
这种形式的
|
将指定为
|
将给定的 SQL 标量值转换为 JSON 标量值。如果输入为 NULL,则SQL返回 null。如果输入是数字或布尔值,则返回相应的 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 对象中键的 set。
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 值中递归删除所有具有空值的字段。没有设定空值的字段不受影响。
|
检查 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
下面在 第 9.16.2.3 部分 中显示了使用路径表达式中的 jsonpath
运算符和方法的其他示例。
路径还可以包含筛选表达式,其工作原理类似于 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"
如果需要,您可以在序列中使用多个筛选表达式。下面的示例选择 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
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
```code``` 运算符(以及 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 数字或字符串中转换得到的数字值
|
从字符串中转换得到的日期/时间值
|
使用指定
|
从字符串中转换得到的日期值
|
无时区的时间值从字符串转换
|
无时区的时间值从字符串转换,小数秒会被调整至给定的精度
|
有时区的时间值从字符串转换
|
有时区的时间值从字符串转换,小数秒会被调整至给定的精度
|
无时区的 Timestamp 值从字符串转换
|
无时区的 Timestamp 值从字符串转换,小数秒会被调整至给定的精度
|
有时区的 Timestamp 值从字符串转换
|
有时区的 Timestamp 值从字符串转换,小数秒会被调整至给定的精度
|
对象的键值对表示为一个数组,对象中包含三个字段:
|
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 常量
|
布尔且
|
布尔 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 数据作为输入时,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
[ 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
子句。在此子句中,您可以通过对行模式应用 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
子句来设置输出格式。请注意,如果同时指定,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
]将通过针对行模式应用 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_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
的用法,用于填充 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_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)
如果您看到文档中的任何内容不正确,不符合您对特定功能的体验或需要进一步澄清,请使用 此表单 报告文档问题。