本节的描述包括
处理和创建 JSON 数据的函数和运算符
SQL/JSON 路径语言
SQL/JSON 查询函数
为在 SQL 环境中以本机方式支持 JSON 数据类型,PostgreSQL 实现SQL/JSON 数据模型。该模型由项序列组成。每个项都可以保存 SQL 标量值、一个额外的 SQL/JSON null 值以及使用 JSON 数组和对象的复合数据结构。该模型是 JSON 规范 RFC 7159 中的隐含数据模型的形式化。
SQL/JSON允许您处理类似于常规SQL数据的JSON数据,并提供事务支持,其中包含
将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 值是否包含第二个 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 数组。行为与
|
从一系列
|
将 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 对象中的键的集合。
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 值(content item),请在路径表达式中使用 $
变量。路径的第一个元素必须始终为 $
。它后面可以跟一个或多个 访问器运算符,这些访问器运算符逐层向下遍历 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]
每个路径评估步骤的结果都可以由 jsonpath
运算符处理,其中一种或多种运算符列于 第 9.16.2.3 节 所示。每个方法名称前面必须带有一个圆点。例如,您可以获取数组的大小
=>
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"
如果需要,您可以按顺序使用多个过滤表达式。下面的示例选择所有包含具有相关坐标的位置且心率值较高的段的开始时间
=>
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 标准在以下方面存在差异。
作为一个对产品标准的扩展,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 数字或字符串转换而来的数字
|
从字符串转换而来的日期/时间值
|
使用指定的
|
从字符串转换而来的日期值
|
从字符串转换而来的时间值(不含时区)
|
从字符串转换而来的时间值(不含时区),小数秒调整为给定的精度
|
从字符串转换而来的时间值(含时区)
|
从字符串转换而来的时间值(含时区),小数秒调整为给定的精度
|
从字符串转换的无时区timestamp值
|
从字符串转换的无时区timestamp值,小数秒已调整到给定的精度
|
从字符串转换的带时区timestamp值
|
从字符串转换的带时区timestamp值,小数秒已调整到给定的精度
|
对象的键值对,表示为一个包含三个字段的对象数组:
|
datetime()
和datetime(
方法的结果类型可以是模板
)date
、timetz
、time
、timestamptz
或timestamp
。这两种方法都动态地确定它们的结果类型。
方法 datetime()
顺序尝试将其输入字符串与 date
、timetz
、time
、timestamptz
以及 timestamp
的 ISO 格式匹配。会在第一个匹配的格式上停止,并发出对应的数据类型。
方法 datetime(
根据在提供的模板字符串中使用的字段确定结果类型。template
)
方法 datetime()
和 datetime(
使用的解析规则与 SQL 函数 template
)to_timestamp
相同(请参阅 第 9.8 节),但有三个例外。首先,这些方法不允许不匹配的模板模式。其次,模板字符串中只允许以下分隔符:减号、句点、斜杠、逗号、单引号、分号、冒号和空格。第三,模板字符串的分隔符必须与输入字符串完全匹配。
如果需要比较不同的日期/时间类型,则会应用隐式强制转换。可以将 date
值强制转换为 timestamp
或 timestamptz
,可以将 timestamp
强制转换为 timestamptz
,可以将 time
强制转换为 timetz
。但是,除了第一次转换外,其余转换都取决于当前 TimeZone 设置,因此只能在时区感知的 jsonpath
函数内执行。同样,将字符串转换为日期/时间类型的其他日期/时间相关方法也会执行此强制转换,其中可能涉及当前 TimeZone 设置。因此,这些转换也只能在时区感知的 jsonpath
函数内执行。
表 9.51 显示了可用的筛选表达式元素。
表 9.51. jsonpath
筛选表达式元素
谓词/值 描述 示例 |
---|
相等性比较(该运算符与其他比较运算符均适用于所有 JSON 标量值)
|
非等值比较
|
小于比较
|
小于或等于比较
|
大于比较
|
大于或等于比较
|
JSON 常量
|
JSON 常量
|
JSON 常量
|
布尔 AND
|
布尔 OR
|
布尔非
|
测试布尔条件是否是
|
根据第二个操作数给出的正则表达式,选择性地使用一系列
|
测试第二个操作数是否是第一个操作数的初始子字符串。
|
测试路径表达式是否至少匹配一个 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
筛选器是使用 POSIX 正则表达式引擎实现的,该引擎在 第 9.7.3 节 中进行了说明。这导致了与标准 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. |
示例
|
如果表达式不是 jsonb
类型,context_item
表达式将被隐式转换并转换成 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 数据为输入,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
[, ...] )
下面将详细描述每个语法元素。
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“同级连接”,还显示在 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)