本节描述
处理和创建 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.47 显示了可用于 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.47。json
和 jsonb
运算符
运算符 描述 示例 |
---|
提取 JSON 数组的第
|
提取具有给定键的 JSON 对象字段。
|
提取 JSON 数组的第
|
提取具有给定键的 JSON 对象字段,作为
|
在指定路径提取 JSON 子对象,其中路径元素可以是字段键或数组索引。
|
将指定路径的 JSON 子对象提取为
|
如果 JSON 输入不具有与请求匹配的正确结构,例如不存在此类键或数组元素,则字段/元素/路径提取运算符返回 NULL,而不是失败。
如 表 9.48 所示,还有一些运算符仅适用于 jsonb
。第 8.14.4 节 描述了如何使用这些运算符有效地搜索索引的 jsonb
数据。
表 9.48。附加 jsonb
运算符
运算符 描述 示例 |
---|
第一个 JSON 值是否包含第二个?(有关包含的详细信息,请参阅 第 8.14.3 节。)
|
第一个 JSON 值是否包含在第二个中?
|
文本字符串作为顶层键或数组元素是否存在于 JSON 值中?
|
文本数组中的任何字符串作为顶层键或数组元素是否存在?
|
文本数组中的所有字符串作为顶层键或数组元素是否存在?
|
连接两个
要将一个数组作为单个条目附加到另一个数组,请将其包装在额外的数组层中,例如
|
从 JSON 对象中删除一个键(及其值),或从 JSON 数组中删除匹配的字符串值。
|
从左操作数中删除所有匹配的键或数组元素。
|
删除具有指定索引的数组元素(负整数从末尾开始计数)。如果 JSON 值不是数组,则抛出错误。
|
删除指定路径处的字段或数组元素,其中路径元素可以是字段键或数组索引。
|
JSON 路径是否为指定的 JSON 值返回任何项?(这仅对 SQL 标准 JSON 路径表达式有用,对谓词检查表达式无效,因为它们总是返回一个值。)
|
返回指定 JSON 值的 JSON 路径谓词检查结果。(这仅对谓词检查表达式有用,对 SQL 标准 JSON 路径表达式无效,因为如果路径结果不是单个布尔值,它将返回
|
jsonpath
运算符 @?
和 @@
抑制以下错误:缺少对象字段或数组元素、意外的 JSON 项类型、日期时间或数字错误。下面描述的 jsonpath
相关函数也可以被告知抑制这些类型的错误。这种行为在搜索结构不同的 JSON 文档集合时可能会有所帮助。
表 9.49 显示了可用于构造 json
和 jsonb
值的函数。此表中的某些函数具有 RETURNING
子句,该子句指定返回的数据类型。它必须是 json
、jsonb
、bytea
、字符字符串类型(text
、char
或 varchar
),或可以转换为 json
的类型之一。默认情况下,返回 json
类型。
表 9.49。JSON 创建函数
函数 描述 示例 |
---|
将任何 SQL 值转换为
|
将 SQL 数组转换为 JSON 数组。行为与
|
从一系列
|
将 SQL 复合值转换为 JSON 对象。行为与
|
从可变参数列表构建一个可能异构类型的 JSON 数组。每个参数都按照
|
从可变参数列表构建一个 JSON 对象。按照惯例,参数列表由交替的键和值组成。键参数被强制转换为文本;值参数按照
|
构造一个包含所有给定键/值对的 JSON 对象,如果没有给定则为空对象。
|
从文本数组构建 JSON 对象。数组必须具有恰好一个维度且成员数为偶数,在这种情况下,它们被视为交替的键/值对,或者两个维度,使得每个内部数组恰好有两个元素,它们被视为键/值对。所有值都转换为 JSON 字符串。
|
此形式的
|
将指定为
|
将给定的 SQL 标量值转换为 JSON 标量值。如果输入为 NULL,则返回一个SQLnull。如果输入是数字或布尔值,则返回相应的 JSON 数字或布尔值。对于任何其他值,返回 JSON 字符串。
|
将 SQL/JSON 表达式转换为字符或二进制字符串。
|
表 9.50 详细介绍了用于测试 JSON 的 SQL/JSON 工具。
表 9.50。SQL/JSON 测试函数
表 9.51 显示了可用于处理 json
和 jsonb
值的函数。
表 9.51。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") |
用于测试
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 值的对象字段。如果
|
检查 JSON 路径是否为指定的 JSON 值返回任何项。(这仅对 SQL 标准 JSON 路径表达式有用,对谓词检查表达式无效,因为它们总是返回一个值。)如果指定了
|
返回指定 JSON 值的 JSON 路径谓词检查的 SQL 布尔结果。(这仅对谓词检查表达式有用,对 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.53 中。在筛选表达式中,@
变量表示正在考虑的值(即,前一个路径步骤的一个结果)。您可以在 @
之后编写访问器运算符以检索组件项。
例如,假设您想检索所有高于 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 值中的相关元素,而谓词检查表达式返回谓词的单个三值 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
筛选器中使用的正则表达式模式的解释存在细微差别,如 第 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.52 显示了 jsonpath
中可用的运算符和方法。请注意,虽然一元运算符和方法可以应用于前一个路径步骤产生的多个值,但二元运算符(加法等)只能应用于单个值。在宽松模式下,应用于数组的方法将对数组中的每个值执行。例外是 .type()
和 .size()
,它们应用于数组本身。
表 9.52. 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.53 显示了可用的筛选表达式元素。
表 9.53. 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
筛选器是使用 第 9.7.3 节中描述的 POSIX 正则表达式引擎实现的。这导致与标准 SQL/JSON 行为存在各种细微差异,这些差异在 第 9.7.3.8 节中进行了分类。但是请注意,其中描述的标志字母不兼容性不适用于 SQL/JSON,因为它将 XQuery 标志字母转换为与 POSIX 引擎期望的匹配。
请记住,like_regex
的模式参数是一个 JSON 路径字符串字面量,根据 第 8.14.7 节中给出的规则编写。这意味着,特别是您想在正则表达式中使用的任何反斜杠都必须加倍。例如,要匹配根文档中仅包含数字的字符串值
$.* ? (@ like_regex "^\\d+$")
表 9.54 中描述的 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.54. 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
子句提取存储在行模式嵌套级别上的 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
[, ...] )
每个语法元素都将在下面更详细地描述。
上下文项
, 路径表达式
[ AS
json_path_name
] [ PASSING
{ 值
AS
变量名
} [, ...]]
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
具有以下变体
名称
FOR ORDINALITY
添加一个序号列,提供从 1 开始的顺序行编号。每个 NESTED PATH
(参见下文)都会为其任何嵌套序号列获取自己的计数器。
名称
类型
[FORMAT JSON
[ENCODING UTF8
]] [ PATH
路径表达式
]
将通过对行模式应用 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
子句,则为后者。
名称
类型
EXISTS
[ PATH
路径表达式
]将通过对行模式应用 path_expression
获得的布尔值在强制转换为指定的 type
后插入到视图的输出行中。
该值对应于将 PATH
表达式应用于行模式是否产生任何值。
指定的 type
应该可以从 boolean
类型进行转换。
可选地,您可以使用 ON ERROR
指定在 JSON 路径评估期间或将 SQL/JSON 值强制转换为指定类型时发生错误时是抛出错误还是返回指定值。默认是返回布尔值 FALSE
。
此子句在内部转换为 JSON_EXISTS
,并具有相同的语义。
NESTED [ PATH ]
路径表达式
[ 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 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)
如果您在文档中发现任何不正确、与您使用特定功能的经验不符或需要进一步澄清的内容,请使用 此表单 报告文档问题。