SQLite数据库中JSON 函数和运算符(二十七)

返回:SQLite---系列文章目录

上一篇:维护SQLite的私有分支(二十六)

下一篇:SQLite---系列文章目录

​1. 概述

默认情况下,SQLite 支持 29 个函数和 2 个运算符 处理 JSON 值。还有两个表值函数可用于分解 JSON 字符串。

有 25 个标量函数和运算符:

  1. json(json)
  2. jsonb(json)
  3. json_array(value1 ,value2,...)
  4. jsonb_array(value1 ,value2,...)
  5. json_array_length(json )
    json_array_length(json ,path)
  6. json_error_position(json)
  7. json_extract(json ,path,...)
  8. jsonb_extract(json ,path,...)
  9. json -> path
  10. json ->> path
  11. json_insert(json ,path ,value,...)
  12. jsonb_insert(json ,path ,value,...)
  13. json_object(label1 ,value1,...)
  14. jsonb_object(label1 ,value1,...)
  15. json_patch(json1,json2)
  16. jsonb_patch(json1,json2)
  17. json_remove(json ,path,...)
  18. jsonb_remove(json ,path,...)
  19. json_replace(json ,path ,value,...)
  20. jsonb_replace(json ,path ,value,...)
  21. json_set(json ,path ,value,...)
  22. jsonb_set(json ,path ,value,...)
  23. json_type(json )
    json_type(json ,path)
  24. json_valid(json )
    json_valid(json,flags)
  25. json_quote(value)

有四个聚合 SQL 函数

  1. json_group_array(value)
  2. jsonb_group_array(value)
  3. json_group_object(label ,value)
  4. jsonb_group_object(name,value)

这两个表值函数是:

  1. json_each(json )
    json_each(json ,path)
  2. json_tree(json )
    json_tree(json ,path)

2. 在 JSON 支持下编译

默认情况下,JSON 函数和运算符内置于 SQLite 中, 自 SQLite 版本 3.38.0 (2022-02-22) 起。可以省略它们 通过添加 -DSQLITE_OMIT_JSON 编译时选项。之前 版本 3.38.0,JSON 函数是一个扩展,只会 如果 -DSQLITE_ENABLE_JSON1 编译时选项包含在构建中 被包括在内。换句话说,JSON 函数从 选择加入 SQLite 版本 3.37.2 及更早版本以选择退出 SQLite 版本 3.38.0 及更高版本。

3. 接口概述

SQLite将JSON存储为普通文本。 向后兼容性约束意味着 SQLite 只能 存储 NULL、整数、浮点数、文本、 和 BLOB。无法添加新的"JSON"类型。

3.1. JSON参数

对于接受 JSON 作为其第一个参数的函数,该参数 可以是 JSON 对象、数组、数字、字符串或 null。SQLite 数值 values 和 NULL 值分别解释为 JSON 编号和 null。 SQLite 文本值可以理解为 JSON 对象、数组或字符串。 如果 SQLite 文本值不是格式正确的 JSON 对象、数组或 字符串被传递到 JSON 函数中,该函数通常会抛出 一个错误。(此规则的例外情况是 json_valid()json_quote()json_error_position()。

这些例程了解所有 rfc-8259 JSON 语法以及 JSON5 扩展。JSON 文本 这些例程生成的例程始终严格符合规范的 JSON 定义,并且不包含任何 JSON5 或其他扩展名。添加了读取和理解 JSON5 的功能 版本 3.42.0 (2023-05-16). 以前版本的 SQLite 只能读取规范的 JSON。

3.2. JSONB的

从版本 3.45.0 (2024-01-15) 开始,SQLite 允许其 要存储在磁盘上的 JSON 的内部"解析树"表示, 作为 BLOB,采用我们称之为"JSONB"的格式。通过存储 SQLite 的内部 JSON的二进制表示直接在数据库、应用程序中 可以绕过解析和渲染 JSON 的开销,读取和 更新 JSON 值。内部 JSONB 格式也略有使用 更少的磁盘空间,然后文本 JSON。

任何接受文本 JSON 作为输入的 SQL 函数参数也将 接受 JSONB 格式的 BLOB。该函数将操作 在任何一种情况下都是一样的,除了它在以下情况下会运行得更快 输入是 JSONB,因为它不需要运行 JSON 解析器。

大多数返回 JSON 文本的 SQL 函数都有相应的函数 返回等效的 JSONB。返回 JSON 的函数 在文本格式中,以"json_"开头,其功能是 返回以"jsonb_"开头的二进制 JSONB 格式。

3.2.1. JSONB格式

JSONB 是 SQLite 和 仅供 SQLite 内部使用。应用 不应在 SQLite 之外使用 JSONB,也不应尝试对 JSONB 格式。

"JSONB"名称的灵感来自 PostgreSQL,但 SQLite 的 JSONB 的磁盘格式与 PostgreSQL 的磁盘格式不同。 这两种格式具有相同的名称,但不兼容二进制文件。 PostgreSQL JSONB 格式声称提供 O(1) 查找对象和数组中的元素。SQLite 的 JSONB 格式没有 这种说法。SQLite 的 JSONB 具有 O(N) 时间复杂度 SQLite中的大多数操作,就像文本JSON一样。JSONB的优势 SQLite 是它比文本 JSON 更小、更快------可能有几个 快几倍。有空间 磁盘上的JSONB格式,以添加增强功能,并且SQLite的未来版本可能会 include 选项来提供 JSONB 中元素的 O(1) 查找,但没有这样的选项 该功能目前可用。

3.2.2. 处理畸形的 JSONB

SQLite 生成的 JSONB 将始终格式正确。如果你 遵循推荐的做法,并 将 JSONB 视为不透明的 BLOB,那么您就不会有任何问题。但 JSONB 只是一个 BLOB,所以一个淘气的程序员可以设计 BLOB 与 JSONB 类似,但在技术上格式不正确。什么时候 格式错误的 JSONB 被馈送到 JSON 函数中,以下任一 可能发生:

  • SQL 语句可能会中止,并显示"格式错误的 JSON"错误。

  • 如果 JSONB blob 不会影响答案。

  • 可能会返回一个愚蠢或荒谬的答案。

SQLite 处理无效 JSONB 的方式可能会改变 从一个版本的SQLite到下一个版本。系统遵循 垃圾输入/垃圾输出规则:如果馈送 JSON 函数无效 JSONB,你得到一个无效的答案。如果您对 我们的 JSONB 的有效性,请使用 json_valid() 函数进行验证。

我们做出以下承诺: 格式错误的 JSONB 永远不会引起内存 错误或可能导致漏洞的类似问题。 无效的 JSONB 可能会导致疯狂的答案, 或者,它可能会导致查询中止,但不会导致崩溃。

3.3. PATH参数

对于接受 PATH 参数的函数,该 PATH 必须格式正确或 否则,该函数将抛出错误。 格式正确的 PATH 是以 1 开头的文本值 "$"字符后跟零个或多个实例 的"。objectlabel "或"[arrayindex]"。

数组索引 通常是一个非负整数 N 。在 在这种情况下,选择的数组元素是第 N 个元素 数组,从左边的零开始。 数组索引 也可以采用"#- N "的形式 在这种情况下,选择的元素是 右。数组的最后一个元素是"#-1 "。念 "#"字符作为"数组中的元素数"。然后 表达式"#-1"的计算结果为对应于 数组中的最后一个条目。它有时对数组很有用 index 仅为 # 字符,例如在追加 现有 JSON 数组的值:

  • json_set('[0,1,2]','$[#]','new') → '[0,1,2,"new"]'

3.4. VALUE 参数

对于接受" "参数的函数(也称为 "value1 " 和 "value2 "), 这些论点通常被理解 成为带引号并成为 JSON 字符串值的文本字符串 在结果中。即使输入字符串如下所示 格式良好的 JSON,它们仍然被解释为 结果。

但是,如果一个值 参数直接来自另一个参数的结果 JSON 函数或来自 -> 运算符(但不是 ->> 运算符), 则参数被理解为实际的 JSON 和 插入完整的 JSON,而不是带引号的字符串。

例如,在下面对 json_object() 的调用中,value 参数看起来像一个格式正确的 JSON 数组。但是,因为它只是 普通的 SQL 文本,它被解释为文字字符串并添加到 结果为带引号的字符串:

  • json_object('ex','[52,3.14159]') → '{"ex":"[52,3.14159]"}'
  • json_object('ex',('[52,3.14159]'->>'$')) → '{"ex":"[52,3.14159]"}'

但是,如果外部 json_object() 调用中的 value 参数是 另一个 JSON 函数(如 json()json_array())的结果,则 该值被理解为实际的 JSON,并按如下方式插入:

  • json_object('ex',json('[52,3.14159]')) → '{"ex":[52,3.14159]}'
  • json_object('ex',json_array(52,3.14159)) → '{"ex":[52,3.14159]}'
  • json_object('ex','[52,3.14159]'->'$') → '{"ex":[52,3.14159]}'

需要明确的是:"json "参数总是被解释为 JSON 无论该参数的值来自何处。但 "value "参数仅在以下情况下被解释为 JSON: 直接来自另一个 JSON 函数或 -> 运算符

在解释为 JSON 字符串的 JSON 值参数中,Unicode 转义 序列不被视为等同于字符或转义 由表示的 Unicode 码位表示的控制字符。 此类转义序列未进行翻译或特殊处理;他们 被 SQLite 的 JSON 函数视为纯文本。

3.5. 兼容性

此 JSON 库的当前实现使用递归下降 解析 器。为了避免使用过多的堆栈空间,任何具有 超过 1000 级的嵌套被认为是无效的。嵌套限制 RFC-8259 第 9 节允许 JSON 的兼容实现进行深度。

3.6. JSON5扩展

从版本 3.42.0 (2023-05-16) 开始,这些例程将 读取和解释包含 JSON5 扩展的输入 JSON 文本。但是,生成的 JSON 文本 通过这些例程将始终严格符合 JSON 的规范定义

以下是 JSON5 扩展的概要(改编自 JSON5 规范):

  • 对象键可以是不带引号的标识符。
  • 对象可以有一个尾部逗号。
  • 数组可以有一个尾随逗号。
  • 字符串可以单引号。
  • 字符串可以通过转义换行符来跨越多行。
  • 字符串可能包含新的字符转义。
  • 数字可以是十六进制的。
  • 数字可以有前导或尾随小数点。
  • 数字可以是"Infinity"、"-Infinity"和"NaN"。
  • 数字可以以明确的加号开头。
  • 允许使用单行 (//...) 和多行 (/*...*/) 注释。
  • 允许使用其他空格字符。

要将字符串 X 从 JSON5 转换为规范 JSON,请调用 "json(X)"。"json()"函数的输出将是规范的 JSON,而不考虑输入中存在的任何 JSON5 扩展。 为了向后兼容,没有 json_valid(X) 函数 "flags"争论仍在继续 为非规范 JSON 的输入报告 false,即使 输入是函数能够理解的 JSON5。确定 无论输入字符串是否有效 JSON5,都包含 0x02 位 在"flags"参数中json_valid:"json_valid(X,2)"。

这些例程可以理解 JSON5 的所有内容,以及更多内容。 SQLite 通过以下两种方式扩展 JSON5 语法:

  1. 严格的 JSON5 要求 不带引号的对象键必须是 ECMAScript 5.1 IdentifierNames。但很大 需要 Unicode 表和大量代码来确定是否或 not a key 是 ECMAScript 5.1 IdentifierName。出于这个原因, SQLite 允许对象键包含任何 unicode 字符 大于 U+007f,不是空格字符。这放松 "标识符"的定义大大简化了实现,并允许 JSON 解析器更小,运行更快。

  2. JSON5 允许将浮点无穷大表示为 "无穷大"、"-无穷大"或"+无穷大" 正是在这种情况下 - 首字母"I"是大写的,所有其他 字符为小写。SQLite还允许缩写"Inf" 用于代替"Infinity",它允许两个关键字 以大小写字母的任意组合出现。 同样地 JSON5 允许"NaN"表示非数字。SQLite扩展了这一点,也允许 "QNaN"和"SNaN"大写和小写字母的任意组合。 请注意,SQLite 将 NaN、QNaN 和 SNaN 解释为一种替代方案 "null"的拼写。 添加此扩展是因为(我们被告知)存在很多 包含这些非标准表示的 JSON 在野外 对于无穷大和非数字。

3.7. 性能注意事项

大多数 JSON 函数使用 JSONB 进行内部处理。因此,如果 输入是文本,他们首先必须将输入文本翻译成 JSONB。 如果输入已经是 JSONB 格式,则不需要翻译, 可以跳过该步骤,并且性能更快。

出于这个原因, 当一个 JSON 函数的参数由另一个 JSON 函数提供时 JSON函数,通常使用"jsonb_"更有效率 用作参数的函数的变体。

  • ... json_insert(A,'$.b',json(C)) ... ← 效率较低。
  • ... json_insert(A,'$.b',jsonb(C)) ... ←效率更高。

聚合 JSON SQL 函数是此规则的例外。那些 所有函数都使用文本而不是 JSONB 进行处理。所以对于 聚合JSON SQL函数,对参数更有效率 使用"json_"功能而不是"jsonb_"提供 功能。

  • ... json_group_array(json(A))) ... ←效率更高。
  • ... json_group_array(jsonb(A))) ... ←效率较低。

3.8. JSON BLOB 输入错误

如果 JSON 输入是不是 JSONB 的 BLOB,并且看起来像 text JSON 转换为文本时,则将其接受为文本 JSON。 这实际上是原始实现中长期存在的错误 SQLite开发人员不知道。文件指出 JSON 函数的 BLOB 输入应引发错误。但是在 实际实施,只要输入将被接受 因为 BLOB 内容是文本编码中的有效 JSON 字符串 数据库。

当 JSON 例程 在 3.45.0 版本 (2024-01-15) 中重新实现。 这导致了依赖旧应用程序的损坏 行为。(为了捍卫这些应用程序:他们经常被引诱进入 通过 readfile() SQL 函数将 BLOB 用作 JSON 在 CLI 中可用。Readfile() 用于从磁盘文件中读取 JSON, 但 readfile() 返回一个 BLOB。这对他们有用,所以为什么不直接 做吗?

为了向后兼容, 将 BLOB 解释为文本 JSON 的(以前不正确的)遗留行为 如果没有其他解释有效 特此记录在案,并在 版本 3.45.1 (2024-01-30) 和所有后续版本。

4. 功能细节

以下各节提供了有关操作的更多详细信息 各种 JSON 函数和运算符:

4.1. json()函数

json(X) 函数验证其参数 X 是否有效 JSON 字符串或 JSONB blob,并返回该 JSON 字符串的缩小版本 删除了所有不必要的空格。如果 X 不是格式良好的 JSON 字符串或 JSONB blob,则此例程会引发错误。

如果输入是 JSON5 文本,则将其转换为规范文本 RFC-8259 文本之前返回。

如果参数 X 到 json(X) 包含重复的 JSON 对象 标签,则未定义重复项是否是 保存。当前实现保留重复项。 但是,未来的增强功能 对于此例程,可以选择静默删除重复项。

例:

  • json(' { "this" : "is", "a": [ "test" ] } ') → '{"this":"is","a":["test"]}'

4.2. jsonb()函数

jsonb(X) 函数返回二进制 JSONB 表示形式 作为参数 X 提供的 JSON。如果 X 是 没有有效 JSON 语法的 TEXT。

如果 X 是 BLOB 并且显示为 JSONB, 那么这个例程只返回一个 X 的副本。 但是,仅检查 JSONB 输入的最外层元素。 JSONB 的深层结构未经过验证。

4.3. json_array() 函数

json_array() SQL 函数接受零个或多个参数,并且 返回由这些参数组成的格式正确的 JSON 数组。 如果 json_array() 的任何参数是 BLOB,则会引发错误。

SQL 类型为 TEXT 的参数通常转换为带引号的参数 JSON 字符串。但是,如果参数是另一个 json1 的输出 函数,则将其存储为 JSON。这允许调用 json_array() 和 json_object() 要嵌套。json() 函数还可以 用于强制将字符串识别为 JSON。

例子:

  • json_array(1,2,'3',4) → '[1,2,"3",4]'
  • json_array('[1,2]') → '["[1,2]"]'
  • json_array(json_array(1,2)) → '[[1,2]]'
  • json_array(1,null,'3','[4,5]','{"six":7.7}') → '[1,null,"3","[4,5]","{\"six\":7.7}"]'
  • json_array(1,null,'3',json('[4,5]'),json('{"six":7.7}')) → '[1,null,"3",[4,5],{"six":7.7}]'

4.4. jsonb_array()函数

jsonb_array()SQL 函数的工作方式与 json_array() 函数类似,只是它返回 SQLite的私有JSONB格式,而不是标准格式 RFC 8259 文本格式。

4.5. json_array_length()函数

json_array_length(X) 函数返回元素数 在 JSON 数组 X 中,如果 X 是某种 JSON 值,则为 0 其他 比数组。json_array_length(X,P) 将数组定位在路径 P 处 在 X 中并返回该数组的长度,如果路径 P 定位,则返回 0 X 中不是 JSON 数组的元素,如果路径 P 不是 NULL 找到 X 的任何元素。如果任一 X 不是,则会引发错误 格式正确的 JSON,或者如果 P 不是格式正确的路径。

例子:

  • json_array_length('[1,2,3,4]') → 4
  • json_array_length('[1,2,3,4]', '$') → 4
  • json_array_length('[1,2,3,4]', '$[2]') → 0
  • json_array_length('{"one":[1,2,3]}') → 0
  • json_array_length('{"one":[1,2,3]}', '$.one') → 3
  • json_array_length('{"one":[1,2,3]}', '$.two') → NULL

4.6. json_error_position()函数

json_error_positionf如果输入 X 为 格式正确的 JSON 或 JSON5 字符串。如果输入 X 包含一个或多个 语法错误,则此函数返回 第一个语法错误。最左边的字符是位置 1。

如果输入 X 是 BLOB,则如果 X 是 格式正确的 JSONB blob。如果返回值为正,则 表示 BLOB 中从 1 开始的近似位置 首次检测到错误。

添加了 json_error_position()函数 SQLite 版本 3.42.0 (2023-05-16).

4.7. json_extract()函数

json_extract(X,P1,P2,...) 提取并返回一个或多个 值从 X 处格式良好的 JSON。如果只提供了单个路径 P1,则 对于 JSON null、INTEGER 或 REAL,结果的 SQL 数据类型为 NULL 对于 JSON 数值,对于 JSON false 值,INTEGER 零, 一个 INTEGER 一个表示 JSON true 值,一个 JSON 字符串值,以及 JSON 对象和数组值的文本表示形式。 如果有多个路径参数(P1、P2 等),那么这个 例程返回 SQLite 文本,该文本是一个格式良好的 JSON 数组,保存 各种值。

例子:

  • json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$') → '{"a":2,"c":[4,5,{"f":7}]}'
  • json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c') → '[4,5,{"f":7}]'
  • json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2]') → '{"f":7}'
  • json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.c[2].f') → 7
  • json_extract('{"a":2,"c":[4,5],"f":7}','.c','.a') → '[[4,5],2]'
  • json_extract('{"a":2,"c":[4,5],"f":7}','$.c[#-1]') → 5
  • json_extract('{"a":2,"c":[4,5,{"f":7}]}', '$.x') → NULL
  • json_extract('{"a":2,"c":[4,5,{"f":7}]}', '.x', '.a') → '[null,2]'
  • json_extract('{"a":"xyz"}', '$.a') → 'xyz'
  • json_extract('{"a":null}', '$.a') → NULL

json_extract()函数之间存在微妙的不兼容性 在 SQLite 和 MySQL 中的 json_extract()函数。MySQL版本 of json_extract()始终返回 JSON。SQLite 版本 json_extract() 仅在存在两个或多个 PATH 参数时返回 JSON (因为结果是一个 JSON 数组)或者如果单个 PATH 参数 引用数组或对象。在SQLite中,如果json_extract()只有 单个 PATH 参数,并且该 PATH 引用 JSON null 或字符串 或数值,则 json_extract()返回相应的 SQL NULL、TEXT、INTEGER 或 REAL 值。

MySQL json_extract()和 SQLite json_extract()之间的区别 只有在访问 JSON 中的单个值时才真正脱颖而出 是字符串或 NULL。下表演示了差异:

操作 SQLite 结果 MySQL 结果
json_extract('{"a":null,"b":"xyz"}','$.a') "空"
json_extract('{"a":null,"b":"xyz"}','$.b') "xyz" '"xyz"'

4.8. jsonb_extract()函数

jsonb_extract()函数的工作方式与 json_extract() 函数相同, 除非 json_extract() 通常会返回文本 JSON 数组对象,此例程返回 JSONB 格式。对于文本、数字、null 或 返回布尔 JSON 元素,此例程的工作方式完全相同 如 json_extract()。

4.9. -> 和 ->> 运算符

从 SQLite 版本 3.38.0 (2022-02-22) 开始,-> 和 ->> 运算符可用于提取 JSON 的子组件。 -> 和 ->> 的 SQLite 实现力求 与 MySQL 和 PostgreSQL 兼容。 -> 和 ->> 运算符采用 JSON 字符串或 JSONB blob 作为其左操作数和 PATH 表达式或对象字段 label 或 array index 作为其右操作数。-> 运算符 返回所选子组件的文本 JSON 表示形式,或者 如果该子组件不存在,则为 NULL。->> 运算符返回 一个 SQL TEXT、INTEGER、REAL 或 NULL 值,表示所选 子组件,如果子组件不存在,则为 NULL。

-> 和 ->> 运算符都选择相同的子组件 JSON在他们左边。区别在于 -> 总是返回一个 该子组件和 ->> 运算符的 JSON 表示形式始终如此 返回该子组件的 SQL 表示形式。因此,这些运算符 与双参数 json_extract() 函数调用略有不同。 使用两个参数调用 json_extract() 将返回 JSON 表示形式 当且仅当子组件是 JSON 数组或 对象,如果 subcomponent 是 JSON 空值、字符串值或数值。

当 -> 运算符返回 JSON 时,它始终返回 该 JSON 的 RFC 8565 文本表示形式,而不是 JSONB。使用 jsonb_extract() 函数,如果您需要 JSONB 格式。

-> 和 ->> 运算符的右操作数可以 是格式正确的 JSON 路径表达式。这是MySQL使用的形式。 为了与 PostgreSQL 兼容, -> 和 ->> 运算符也接受文本对象标签或 整数数组索引作为其右手操作数。 如果正确的操作数是文本 标签 X,则将其解释为 JSON 路径 '。X'.如果正确的 operand 是一个整数值 N,则将其解释为 JSON 路径"[N]"。

例子:

  • '{"a":2,"c":[4,5,{"f":7}]}' -> '$' → '{"a":2,"c":[4,5,{"f":7}]}'
  • '{"a":2,"c":[4,5,{"f":7}]}' -> '$.c' → '[4,5,{"f":7}]'
  • '{"a":2,"c":[4,5,{"f":7}]}' -> 'c' → '[4,5,{"f":7}]'
  • '{"a":2,"c":[4,5,{"f":7}]}' -> '$.c[2]' → '{"f":7}'
  • '{"a":2,"c":[4,5,{"f":7}]}' -> '$.c[2].f' → '7'
  • '{"a":2,"c":[4,5,{"f":7}]}' ->> '$.c[2].f' → 7
  • '{"a":2,"c":[4,5,{"f":7}]}' -> 'c' -> 2 ->> 'f' → 7
  • '{"a":2,"c":[4,5],"f":7}' -> '$.c[#-1]' → '5'
  • '{"a":2,"c":[4,5,{"f":7}]}' -> '$.x' → NULL
  • '[11,22,33,44]' -> 3 → '44'
  • '[11,22,33,44]' ->> 3 → 44
  • '{"a":"xyz"}' -> '$.a' → '"xyz"'
  • '{"a":"xyz"}' ->> '$.a' → 'xyz'
  • '{"a":null}' -> '$.a' → 'null'
  • '{"a":null}' ->> '$.a' → NULL

4.10. json_insert()、json_replace 和 json_set()函数

json_insert()、json_replace 和 json_set()函数都采用 单个 JSON 值作为其第一个参数,后跟零或更多 路径和值参数对,并返回形成的新 JSON 字符串 通过路径/值对更新输入 JSON。主要工作内容 区别仅在于它们如何处理创建新值和覆盖 预先存在的值。

功能 如果已经存在,请覆盖? 如果不存在,请创建?
json_insert() 是的
json_replace() 是的
json_set() 是的 是的

json_insert()、json_replace() 和 json_set() 函数始终 取奇数个参数。第一个参数始终是原始参数 要编辑的 JSON。后续参数与第一个参数成对出现 每对元素是路径,第二个元素是值 插入、替换或设置该路径。

编辑从左到右依次进行。由以下原因引起的更改 先前的编辑可能会影响后续编辑的路径搜索。

如果路径/值对的值是 SQLite TEXT 值,则它 通常作为带引号的 JSON 字符串插入,即使该字符串看起来 就像有效的 JSON 一样。但是,如果该值是另一个的结果 json 函数(例如 json()json_array()json_object()) 或者如果它是 -> 运算符的结果, 然后将其解释为 JSON,并作为 JSON 插入,保留所有 其下部结构。作为 ->> 运算符的结果的值始终被解释为 TEXT,甚至入为 JSON 字符串 如果它们看起来像有效的 JSON。

如果第一个 JSON 参数不是,则这些例程会引发错误 格式正确,或者如果任何 PATH 参数格式不正确,或者如果有 参数是一个 BLOB。

要将元素附加到数组的末尾,请使用 json_insert() 数组索引为"#"。例子:

  • json_insert('[1,2,3,4]','$[#]',99) → '[1,2,3,4,99]'
  • json_insert('[1,[2,3],4]','$[1][#]',99) → '[1,[2,3,99],4]'

其他示例:

  • json_insert('{"a":2,"c":4}', '$.a', 99) → '{"a":2,"c":4}'
  • json_insert('{"a":2,"c":4}', '$.e', 99) → '{"a":2,"c":4,"e":99}'
  • json_replace('{"a":2,"c":4}', '$.a', 99) → '{"a":99,"c":4}'
  • json_replace('{"a":2,"c":4}', '$.e', 99) → '{"a":2,"c":4}'
  • json_set('{"a":2,"c":4}', '$.a', 99) → '{"a":99,"c":4}'
  • json_set('{"a":2,"c":4}', '$.e', 99) → '{"a":2,"c":4,"e":99}'
  • json_set('{"a":2,"c":4}', '$.c', '[97,96]') → '{"a":2,"c":"[97,96]"}'
  • json_set('{"a":2,"c":4}', '$.c', json('[97,96]')) → '{"a":2,"c":[97,96]}'
  • json_set('{"a":2,"c":4}', '$.c', json_array(97,96)) → '{"a":2,"c":[97,96]}'

4.11. jsonb_insert()、jsonb_replace 和 jsonb_set()函数

jsonb_insert()、jsonb_replace()和 jsonb_set()函数的工作方式是 分别与 json_insert()、json_replace()json_set() 相同, 除了"jsonb_"版本以二进制文件返回其结果 JSONB 格式。

4.12. json_object()函数

json_object()SQL 函数接受零对或多对参数 并返回由这些参数组成的格式正确的 JSON 对象。 每对的第一个参数是标签,第二个参数是 每对都是值。 如果 json_object()的任何参数是 BLOB,则会引发错误。

json_object()函数目前允许重复标签,而没有 投诉,尽管这可能会在将来的增强功能中发生变化。

具有 SQL 类型 TEXT 的参数,通常将其转换为带引号的 JSON 字符串,即使输入文本格式正确为 JSON。 但是,如果参数是另一个 JSON 的直接结果 函数或 -> 运算符(但不是 ->> 运算符), 然后将其视为 JSON 及其所有 JSON 类型信息 并保留了下部结构。这允许调用 json_object()和 json_array() 要嵌套。json() 函数还可以 用于强制将字符串识别为 JSON。

例子:

  • json_object('a',2,'c',4) → '{"a":2,"c":4}'
  • json_object('a',2,'c','{e:5}') → '{"a":2,"c":"{e:5}"}'
  • json_object('a',2,'c',json_object('e',5)) → '{"a":2,"c":{"e":5}}'

4.13. jsonb_object()函数

jsonb_object()函数的工作方式与 json_object() 函数类似 除了生成的对象以二进制 JSONB 格式返回。

4.14. json_patch()函数

json_patch(T,P) SQL 函数运行 RFC-7396 MergePatch 算法 对输入 T 应用补丁 P。返回 T 的修补副本。

MergePatch 可以添加、修改或删除 JSON 对象的元素, 因此,对于 JSON 对象,json_patch() 例程是通用的 替换 json_set()json_remove()。但是,MergePatch 将 JSON 数组对象视为原子对象。MergePatch 不能附加到 数组,也不修改数组的单个元素。它只能插入, 替换或删除整个数组作为单个单元。因此,json_patch() 在处理包含数组的 JSON 时没有那么有用, 尤其是具有大量子结构的数组。

例子:

  • json_patch('{"a":1,"b":2}','{"c":3,"d":4}') → '{"a":1,"b":2,"c":3,"d":4}'
  • json_patch('{"a":[1,2],"b":2}','{"a":9}') → '{"a":9,"b":2}'
  • json_patch('{"a":[1,2],"b":2}','{"a":null}') → '{"b":2}'
  • json_patch('{"a":1,"b":2}','{"a":9,"b":null,"c":8}') → '{"a":9,"c":8}'
  • json_patch('{"a":{"x":1,"y":2},"b":3}','{"a":{"y":9},"c":8}') → '{"a":{"x":1,"y":9},"b":3,"c":8}'

4.15. jsonb_patch()函数

jsonb_patch() 函数的工作方式与 json_patch() 函数类似 除了修补后的 JSON 以二进制 JSONB 格式返回。

4.16. json_remove()数

json_remove(X,P,...) 函数采用单个 JSON 值作为其 第一个参数后跟零个或多个路径参数。 json_remove(X,P,...) 函数返回 包含所有元素的 X 参数的副本 由删除的路径参数标识。选择元素的路径 在 X 中找不到将被静默忽略。

移除从左到右依次进行。由以下原因引起的更改 先前的删除可能会影响后续参数的路径搜索。

如果调用 json_remove(X) 函数时没有路径参数, 然后它返回重新格式化的输入 X,其中包含多余的空格 删除。

如果第一个参数,则 json_remove()函数会抛出错误 不是格式正确的 JSON,或者如果任何后面的参数不是格式正确的 路径。

例子:

  • json_remove('[0,1,2,3,4]','$[2]') → '[0,1,3,4]'
  • json_remove('[0,1,2,3,4]','\[2\]','[0]') → '[1,3,4]'
  • json_remove('[0,1,2,3,4]','\[0\]','[2]') → '[1,2,4]'
  • json_remove('[0,1,2,3,4]','\[#-1\]','[0]') → '[1,2,3]'
  • json_remove('{"x":25,"y":42}') → '{"x":25,"y":42}'
  • json_remove('{"x":25,"y":42}','$.z') → '{"x":25,"y":42}'
  • json_remove('{"x":25,"y":42}','$.y') → '{"x":25}'
  • json_remove('{"x":25,"y":42}','$') → NULL

4.17. jsonb_remove()函数

jsonb_remove() 函数的工作方式与 json_remove() 函数类似 除了编辑后的 JSON 结果以二进制 JSONB 格式返回。

4.18. json_type()函数

json_type(X) 函数返回最外层元素的"类型" 的 X。json_type(X,P) 函数返回元素的"类型" 在 X 中,由路径 P 选择。json_type() 返回的"类型"是 以下 SQL 文本值之一: 'null', 'true', 'false', 'integer', 'real', 'text', 'array' 或 'object'。 如果 json_type(X,P) 中的路径 P 选择了不存在的元素 在 X 中,则此函数返回 NULL。

如果 json_type()函数的第一个参数为 格式不正确的 JSON 或 JSONB,或者它的第二个参数格式不正确 JSON 路径。

例子:

  • json_type('{"a":[2,3.5,true,false,null,"x"]}') → 'object'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$') → 'object'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a') → 'array'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[0]') → 'integer'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[1]') → 'real'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[2]') → 'true'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[3]') → 'false'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[4]') → 'null'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[5]') → 'text'
  • json_type('{"a":[2,3.5,true,false,null,"x"]}','$.a[6]') → NULL

4.19. json_valid()函数

如果参数 X 格式正确,则 json_valid(X,Y) 函数返回 1 JSON,如果 X 格式不正确,则返回 0。Y 参数是一个整数 位掩码,用于定义"格式正确"的含义。以下位 的 Y 目前定义:

  • 0x01→ 输入是严格符合规范 RFC-8259 JSON 的文本, 没有任何扩展名。
  • 0x02 → 输入是具有上述 JSON5 扩展名的 JSON 文本。
  • 0x04 → 输入是一个 BLOB,表面上看起来是 JSONB
  • 0x08 → 输入是严格符合内部 JSONB 格式的 BLOB。

通过组合位,可以导出以下有用的 Y 值:

  • 1 → X 是 RFC-8259 JSON 文本
  • 2 → X 是 JSON5 文本
  • 4 → X 可能是 JSONB
  • 5 → X 是 RFC-8259 JSON 文本或 JSONB
  • 6 → X 是 JSON5 文本或 JSONB这可能是您想要的值
  • 8 → X 严格符合 JSONB
  • 9 → X 是 RFC-8259 或严格符合 JSONB
  • 10 → X 是 JSON5 或严格符合 JSONB

Y 参数是可选的。如果省略,则默认为 1,这意味着 默认行为是仅当输入 X 为 严格符合 RFC-8259 JSON 文本,不带任何扩展名。这 使 json_valid() 的单参数版本与旧的 SQLite 版本,在添加对 JSON5JSONB 的支持之前。

Y 参数中 0x04 位和 0x08 位的区别在于 0x04 只检查 BLOB 的外部包装,看看它是否表面上 看起来像 JSONB。这对于必须的目的来说已经足够了,而且速度非常快。 0x08位对 BLOB 的所有内部细节进行彻底检查。 0x08位所需的时间与 X 输入的大小呈线性关系,并且非常大 慢。大多数用途都建议使用 0x04 位。

如果您只是想知道一个值是否是以下之一的合理输入 其他 JSON 函数,Y 值 6 可能是您想要使用的。

任何小于 1 或大于 15 的 Y 值都会引发错误,因为 json_valid() 的最新版本。但是,json_valid() 的未来版本 可能会增强为接受超出此范围的标志值,具有新的 我们还没有想到的含义。

如果 json_valid() 的 X 或 Y 输入为 NULL,则函数 返回 NULL。

例子:

  • json_valid('{"x":35}') → 1
  • json_valid('{x:35}') → 0
  • json_valid('{x:35}',6) → 1
  • json_valid('{"x":35') → 0
  • json_valid(NULL) → NULL

4.20. json_quote() 函数

json_quote(X) 函数转换 SQL 值 X(数字或 string) 转换为其对应的 JSON 表示形式。如果 X 是 JSON 值 由另一个 JSON 函数返回,则此函数是 no-op。

例子:

  • json_quote(3.14159) → 3.14159
  • json_quote('verdant') → '"verdant"'
  • json_quote('[1]') → '"[1]"'
  • json_quote(json('[1]')) → '[1]'
  • json_quote('[1,') → '"[1,"'

4.21. 数组和对象聚合函数

json_group_array(X) 函数是一个聚合 SQL 函数,返回一个 JSON 数组 由聚合中的所有 X 值组成。 同样,json_group_object(NAME,VALUE) 函数返回一个 JSON 对象 由聚合中的所有 NAME/VALUE 对组成。 "jsonb_"变体是相同的,只是它们返回 结果为二进制 JSONB 格式。

4.22. json_each()和 json_tree()表值函数

json_each(X) 和 json_tree(X) 表值函数遍历 JSON 值作为其第一个参数提供,并为每个参数返回一行 元素。json_each(X) 功能仅引导直系子女 顶级数组或对象, 或者只是顶级元素本身,如果顶级 元素是基元值。 json_tree(X) 函数递归遍历 从顶级元素开始的 JSON 子结构。

json_each(X,P) 和 json_tree(X,P) 函数的工作方式与 他们的单参数对应物,除了他们处理元素 由路径 P 标识为顶级元素。

json_each() 和 json_tree() 返回的表的架构为 如下:

sql 复制代码
CREATE TABLE json_tree(
    key ANY,             -- key for current element relative to its parent
    value ANY,           -- value for the current element
    type TEXT,           -- 'object','array','string','integer', etc.
    atom ANY,            -- value for primitive types, null for array & object
    id INTEGER,          -- integer ID for this element
    parent INTEGER,      -- integer ID for the parent of this element
    fullkey TEXT,        -- full path describing the current element
    path TEXT,           -- path to the container of the current row
    json JSON HIDDEN,    -- 1st input parameter: the raw JSON
    root TEXT HIDDEN     -- 2nd input parameter: the PATH at which to start
);

"key"列是 JSON 数组元素的整数数组索引 以及 JSON 对象元素的文本标签。键列是 在所有其他情况下为 NULL。

"atom"列是原元元素对应的 SQL 值 - JSON 数组和对象以外的元素。"atom"列为 NULL 用于 JSON 数组或对象。"value" 列与 "atom"列用于原始 JSON 元素,但采用文本 JSON 值 用于数组和对象。

"type"列是从 ('null', 'true', 'false', 'integer', 'real', 'text', 'array', 'object') 当前 JSON 元素。

"id"列是一个整数,用于标识特定的 JSON 元素 在完整的 JSON 字符串中。"id"整数是内部内务管理 number,其计算方法可能会在将来的版本中发生变化。这 唯一可以保证的是每一行的"id"列都不同。

对于 json_each(),"parent"列始终为 NULL。 对于 json_tree(), "parent"列是当前父项的"id"整数 元素,或顶级 JSON 元素或标识的元素的 NULL 通过第二个参数中的根路径。

"fullkey"列是唯一标识当前 原始 JSON 字符串中的 row 元素。完整的钥匙 即使有替代起点,也会返回 True 顶级元素 由"root"参数提供。

"path"列是保存数组或对象容器的路径 当前行,或当前行的路径,如果 迭代从基元类型开始,因此仅提供单个 输出行。

4.22.1. 使用 json_each()和 json_tree()的示例

假设表"CREATE TABLE user(name,phone)"存储零或 更多电话号码作为 user.phone 字段中的 JSON 数组对象。 要查找拥有任何带有 704 区号的电话号码的所有用户:

sql 复制代码
SELECT DISTINCT user.name
  FROM user, json_each(user.phone)
 WHERE json_each.value LIKE '704-%';

现在假设 user.phone 字段包含纯文本,如果用户 只有一个电话号码和一个 JSON 数组(如果用户有多个电话号码) 电话号码。提出了同样的问题:"哪些用户有电话号码 在704区号中?但是现在只能调用 json_each() 函数 对于自 json_each()以来拥有两个或更多电话号码的用户 需要格式正确的 JSON 作为其第一个参数:

sql 复制代码
SELECT name FROM user WHERE phone LIKE '704-%'
UNION
SELECT user.name
  FROM user, json_each(user.phone)
 WHERE json_valid(user.phone)
   AND json_each.value LIKE '704-%';

考虑使用"CREATE TABLE big(json JSON)"的不同数据库。 要查看数据的完整逐行分解,请执行以下操作:

sql 复制代码
SELECT big.rowid, fullkey, value
  FROM big, json_tree(big.json)
 WHERE json_tree.type NOT IN ('object','array');

在前面的"type NOT IN ('object','array')"项中 WHERE 子句禁止容器,只允许通过叶元素。 可以通过以下方式实现相同的效果:

sql 复制代码
SELECT big.rowid, fullkey, atom
  FROM big, json_tree(big.json)
 WHERE atom IS NOT NULL;

假设 BIG 表中的每个条目都是一个 JSON 对象 带有唯一标识符的".id"字段 以及可以是深度嵌套对象的".partlist"字段。 您希望查找包含 或更多引用 UUID '6fa5181e-5721-11e5-a04e-57f3d7b32808' 在其"$.partlist"中。

sql 复制代码
SELECT DISTINCT json_extract(big.json,'$.id')
  FROM big, json_tree(big.json, '$.partlist')
 WHERE json_tree.key='uuid'
   AND json_tree.value='6fa5181e-5721-11e5-a04e-57f3d7b32808';
相关推荐
獨枭1 小时前
CMake 构建项目并整理头文件和库文件
c++·github·cmake
靖顺2 小时前
【OceanBase 诊断调优】—— packet fly cost too much time 的根因分析
数据库·oceanbase
liuxin334455662 小时前
学籍管理系统:实现教育管理现代化
java·开发语言·前端·数据库·安全
小王爱吃月亮糖2 小时前
C++的23种设计模式
开发语言·c++·qt·算法·设计模式·ecmascript
小哈龙4 小时前
c++ 类似与c# 线程 AutoResetEvent 和 ManualResetEvent的实现
c++·c#·多线程
yuanbenshidiaos5 小时前
C++--------------树
java·数据库·c++
海螺姑娘的小魏5 小时前
Effective C++ 条款 15:在资源管理类中提供对原始资源的访问
开发语言·c++
dengjiayue6 小时前
MySQL 查询大偏移量(LIMIT)问题分析
数据库·mysql
言之。6 小时前
【MySQL】在MySQL中如何定位慢查询?
数据库·mysql
DashVector6 小时前
如何通过HTTP API插入Doc
数据库·人工智能·http·阿里云·向量检索