一文说透 MySQL JSON 数据类型(收藏)

JSON 数据类型是 MySQL 5.7.8 开始支持的。在此之前,只能通过字符类型(CHAR,VARCHAR 或 TEXT )来保存 JSON 文档。

相对字符类型,原生的 JSON 类型具有以下优势:

  1. 在插入时能自动校验文档是否满足 JSON 格式的要求。
  2. 优化了存储格式。无需读取整个文档就能快速访问某个元素的值。

在 JSON 类型引入之前,如果我们想要获取 JSON 文档中的某个元素,必须首先读取整个 JSON 文档,然后在客户端将其转换为 JSON 对象,最后再通过对象获取指定元素的值。

下面是 Python 中的获取方式。

import&#xA0;json<br><br>#&#xA0;JSON&#xA0;&#x5B57;&#x7B26;&#x4E32;:<br>x&#xA0;=&#xA0;&#xA0;'{&#xA0;"name":"John",&#xA0;"age":30,&#xA0;"city":"New&#xA0;York"}'<br><br>#&#xA0;&#x5C06;&#xA0;JSON&#xA0;&#x5B57;&#x7B26;&#x4E32;&#x8F6C;&#x6362;&#x4E3A;&#xA0;JSON&#xA0;&#x5BF9;&#x8C61;:<br>y&#xA0;=&#xA0;json.loads(x)<br><br>#&#xA0;&#x8BFB;&#x53D6;&#xA0;JSON&#xA0;&#x5BF9;&#x8C61;&#x4E2D;&#x6307;&#x5B9A;&#x5143;&#x7D20;&#x7684;&#x503C;:<br>print(y["age"])

这种方式有两个弊端:一、消耗磁盘 IO,二、消耗网络带宽,如果 JSON 文档比较大,在高并发场景,有可能会打爆网卡。

如果使用的是 JSON 类型,相同的需求,直接使用 SQL 命令就可搞定。不仅能节省网络带宽,结合后面提到的函数索引,还能降低磁盘 IO 消耗。

mysql>&#xA0;create&#xA0;table&#xA0;t(c1&#xA0;json);<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.09&#xA0;sec)<br><br>mysql>&#xA0;insert&#xA0;into&#xA0;t&#xA0;values('{&#xA0;"name":"John",&#xA0;"age":30,&#xA0;"city":"New&#xA0;York"}');<br>Query&#xA0;OK,&#xA0;1&#xA0;row&#xA0;affected&#xA0;(0.01&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;c1->"$.age"&#xA0;from&#xA0;t;<br>+-------------+<br>|&#xA0;c1->"$.age"&#xA0;|<br>+-------------+<br>|&#xA0;30&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

本文将从以下几个方面展开:

[En]

This article will be carried out from the following aspects:

  1. 什么是 JSON。
  2. JSON 字段的增删改查操作。
  3. 如何对 JSON 字段创建索引。
  4. 如何将存储 JSON 字符串的字符字段升级为 JSON 字段。
  5. 使用 JSON 时的注意事项。
  6. Partial Updates。
  7. 其它 JSON 函数。

一、什么是 JSON

JSON 是 JavaScript Object Notation(JavaScript 对象表示法)的缩写,是一个轻量级的,基于文本的,跨语言的数据交换格式。易于阅读和编写。

JSON 的基本数据类型如下:

  • 数值:十进制数,不能有前导 0,可以为负数或小数,还可以为 e 或 E 表示的指数。
  • 字符串:字符串必须用双引号括起来。
    [En]

    string: the string must be enclosed in double quotation marks.*

  • 布尔值:true,false。
  • 数组:一个由零或多个值组成的有序序列。每个值可以为任意类型。数组使用方括号 [] 括起来,元素之间用逗号 ,分隔。譬如,
[1,&#xA0;"abc",&#xA0;null,&#xA0;true,&#xA0;"10:27:06.000000",&#xA0;{"id":&#xA0;1}]
  • 对象:一个由零或者多个键值对组成的无序集合。其中键必须是字符串,值可以为任意类型。 对象使用花括号 {}括起来,键值对之间使用逗号 ,分隔,键与值之间用冒号 :分隔。譬如,
{"db":&#xA0;["mysql",&#xA0;"oracle"],&#xA0;"id":&#xA0;123,&#xA0;"info":&#xA0;{"age":&#xA0;20}}
  • 空值:null。

二、JSON 字段的增删改查操作

下面我们看看 JSON 字段常见的增删改查操作:

2.1 插入操作

可直接插入 JSON 格式的字符串。

mysql>&#xA0;create&#xA0;table&#xA0;t(c1&#xA0;json);<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.03&#xA0;sec)<br><br>mysql>&#xA0;insert&#xA0;into&#xA0;t&#xA0;values('[1,&#xA0;"abc",&#xA0;null,&#xA0;true,&#xA0;"08:45:06.000000"]');<br>Query&#xA0;OK,&#xA0;1&#xA0;row&#xA0;affected&#xA0;(0.01&#xA0;sec)<br><br>mysql>&#xA0;insert&#xA0;into&#xA0;t&#xA0;values('{"id":&#xA0;87,&#xA0;"name":&#xA0;"carrot"}');<br>Query&#xA0;OK,&#xA0;1&#xA0;row&#xA0;affected&#xA0;(0.01&#xA0;sec)

也可使用函数,常用的有 JSON_ARRAY() 和 JSON_OBJECT(),前者用于构造 JSON 数组,后者用于构造 JSON 对象。如,

mysql>&#xA0;select&#xA0;json_array(1,&#xA0;"abc",&#xA0;null,&#xA0;true,curtime());<br>+--------------------------------------------+<br>|&#xA0;json_array(1,&#xA0;"abc",&#xA0;null,&#xA0;true,curtime())&#xA0;|<br>+--------------------------------------------+<br>|&#xA0;[1,&#xA0;"abc",&#xA0;null,&#xA0;true,&#xA0;"10:12:25.000000"]&#xA0;&#xA0;|<br>+--------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.01&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_object('id',&#xA0;87,&#xA0;'name',&#xA0;'carrot');<br>+-----------------------------------------+<br>|&#xA0;json_object('id',&#xA0;87,&#xA0;'name',&#xA0;'carrot')&#xA0;|<br>+-----------------------------------------+<br>|&#xA0;{"id":&#xA0;87,&#xA0;"name":&#xA0;"carrot"}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-----------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

对于 JSON 文档,KEY 名不能重复。

如果插入的值中存在重复 KEY,在 MySQL 8.0.3 之前,遵循 first duplicate key wins 原则,会保留第一个 KEY,后面的将被丢弃掉。

从 MySQL 8.0.3 开始,遵循的是 last duplicate key wins 原则,只会保留最后一个 KEY。

让我们通过一个具体的例子来看看这两者之间的区别。

[En]

Let’s look at the difference between the two through a concrete example.

MySQL 5.7.36

mysql>&#xA0;select&#xA0;json_object('key1',10,'key2',20,'key1',30);<br>+--------------------------------------------+<br>|&#xA0;json_object('key1',10,'key2',20,'key1',30)&#xA0;|<br>+--------------------------------------------+<br>|&#xA0;{"key1":&#xA0;10,&#xA0;"key2":&#xA0;20}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.02&#xA0;sec)

MySQL 8.0.27

mysql>&#xA0;select&#xA0;json_object('key1',10,'key2',20,'key1',30);<br>+--------------------------------------------+<br>|&#xA0;json_object('key1',10,'key2',20,'key1',30)&#xA0;|<br>+--------------------------------------------+<br>|&#xA0;{"key1":&#xA0;30,&#xA0;"key2":&#xA0;20}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

2.2 查询操作

JSON_EXTRACT(json_doc, path[, path] …)

其中,json_doc 是 JSON 文档,path 是路径。该函数会从 JSON 文档提取指定路径(path)的元素。如果指定 path 不存在,会返回 NULL。可指定多个 path,匹配到的多个值会以数组形式返回。

下面我们结合一些具体的示例来看看 path 及 JSON_EXTRACT 的用法。

首先我们看看数组。

数组的路径由下标表示。第一个元素的下标是0。

[En]

The path to the array is represented by subscript. The subscript of the first element is 0.

mysql>&#xA0;select&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[0]');<br>+--------------------------------------------+<br>|&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[0]')&#xA0;|<br>+--------------------------------------------+<br>|&#xA0;10&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[0]',&#xA0;'$[1]','$[2][0]');<br>+--------------------------------------------------------------+<br>|&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[0]',&#xA0;'$[1]','$[2][0]')&#xA0;|<br>+--------------------------------------------------------------+<br>|&#xA0;[10,&#xA0;20,&#xA0;30]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

除此之外,还可通过 [M to N] 获取数组的子集。

mysql>&#xA0;select&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[0&#xA0;to&#xA0;1]');<br>+-------------------------------------------------+<br>|&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[0&#xA0;to&#xA0;1]')&#xA0;|<br>+-------------------------------------------------+<br>|&#xA0;[10,&#xA0;20]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>#&#xA0;&#x8FD9;&#x91CC;&#x7684;&#xA0;last&#xA0;&#x4EE3;&#x8868;&#x6700;&#x540E;&#x4E00;&#x4E2A;&#x5143;&#x7D20;&#x7684;&#x4E0B;&#x6807;<br>mysql>&#xA0;select&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[last-1&#xA0;to&#xA0;last]');<br>+---------------------------------------------------------+<br>|&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[last-1&#xA0;to&#xA0;last]')&#xA0;|<br>+---------------------------------------------------------+<br>|&#xA0;[20,&#xA0;[30,&#xA0;40]]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

也可通过 [*] 获取数组中的所有元素。

mysql>&#xA0;select&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[*]');<br>+--------------------------------------------+<br>|&#xA0;json_extract('[10,&#xA0;20,&#xA0;[30,&#xA0;40]]',&#xA0;'$[*]')&#xA0;|<br>+--------------------------------------------+<br>|&#xA0;[10,&#xA0;20,&#xA0;[30,&#xA0;40]]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

接下来,我们看看对象。

对象的路径是通过 KEY 来表示的。

mysql>&#xA0;set&#xA0;@j='{"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3],&#xA0;"a&#xA0;c":&#xA0;4}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>#&#xA0;&#x5982;&#x679C; KEY &#x5728;&#x8DEF;&#x5F84;&#x8868;&#x8FBE;&#x5F0F;&#x4E2D;&#x4E0D;&#x5408;&#x6CD5;&#xFF08;&#x8B6C;&#x5982;&#x5B58;&#x5728;&#x7A7A;&#x683C;&#xFF09;&#xFF0C;&#x5219;&#x5728;&#x5F15;&#x7528;&#x8FD9;&#x4E2A; KEY &#x65F6;&#xFF0C;&#x9700;&#x7528;&#x53CC;&#x5F15;&#x53F7;&#x62EC;&#x8D77;&#x6765;&#x3002;<br>mysql>&#xA0;select&#xA0;json_extract(@j,&#xA0;'$.a'),&#xA0;json_extract(@j,&#xA0;'$."a&#xA0;c"'),&#xA0;json_extract(@j,&#xA0;'$.b[1]');<br>+-------------------------+-----------------------------+----------------------------+<br>|&#xA0;json_extract(@j,&#xA0;'$.a')&#xA0;|&#xA0;json_extract(@j,&#xA0;'$."a&#xA0;c"')&#xA0;|&#xA0;json_extract(@j,&#xA0;'$.b[1]')&#xA0;|<br>+-------------------------+-----------------------------+----------------------------+<br>|&#xA0;1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;4&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;3&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-------------------------+-----------------------------+----------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

除此之外,还可通过 .* 获取对象中的所有元素。

mysql>&#xA0;select&#xA0;json_extract('{"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3],&#xA0;"a&#xA0;c":&#xA0;4}',&#xA0;'$.*');<br>+--------------------------------------------------------+<br>|&#xA0;json_extract('{"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3],&#xA0;"a&#xA0;c":&#xA0;4}',&#xA0;'$.*')&#xA0;|<br>+--------------------------------------------------------+<br>|&#xA0;[1,&#xA0;[2,&#xA0;3],&#xA0;4]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>#&#xA0;&#x8FD9;&#x91CC;&#x7684;&#xA0;$**.b&#xA0;&#x5339;&#x914D;&#xA0;$.a.b&#xA0;&#x548C;&#xA0;$.c.b<br>mysql>&#xA0;select&#xA0;json_extract('{"a":&#xA0;{"b":&#xA0;1},&#xA0;"c":&#xA0;{"b":&#xA0;2}}',&#xA0;'$**.b');<br>+---------------------------------------------------------+<br>|&#xA0;json_extract('{"a":&#xA0;{"b":&#xA0;1},&#xA0;"c":&#xA0;{"b":&#xA0;2}}',&#xA0;'$**.b')&#xA0;|<br>+---------------------------------------------------------+<br>|&#xA0;[1,&#xA0;2]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

column->path

column->path,包括后面讲到的 column->>path,都是语法糖,在实际使用的时候都会转化为 JSON_EXTRACT。

column->path 等同于 JSON_EXTRACT(column, path) ,只能指定一个path。

create&#xA0;table&#xA0;t(c2&#xA0;json);<br><br>insert&#xA0;into&#xA0;t&#xA0;values('{"empno":&#xA0;1001,&#xA0;"ename":&#xA0;"jack"}'),&#xA0;('{"empno":&#xA0;1002,&#xA0;"ename":&#xA0;"mark"}');<br><br>mysql>&#xA0;select&#xA0;c2,&#xA0;c2->"$.ename"&#xA0;from&#xA0;t;<br>+----------------------------------+---------------+<br>|&#xA0;c2&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;c2->"$.ename"&#xA0;|<br>+----------------------------------+---------------+<br>|&#xA0;{"empno":&#xA0;1001,&#xA0;"ename":&#xA0;"jack"}&#xA0;|&#xA0;"jack"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>|&#xA0;{"empno":&#xA0;1002,&#xA0;"ename":&#xA0;"mark"}&#xA0;|&#xA0;"mark"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+----------------------------------+---------------+<br>2&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;*&#xA0;from&#xA0;t&#xA0;where&#xA0;c2->"$.empno"&#xA0;=&#xA0;1001;<br>+------+----------------------------------+<br>|&#xA0;c1&#xA0;&#xA0;&#xA0;|&#xA0;c2&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------+----------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;{"empno":&#xA0;1001,&#xA0;"ename":&#xA0;"jack"}&#xA0;|<br>+------+----------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

column->>path

同 column->path 类似,只不过其返回的是字符串。以下三者是等价的。

  • JSON_UNQUOTE( JSON_EXTRACT(column, path) )
  • JSON_UNQUOTE(column -> path)
  • column->>path
mysql>&#xA0;select&#xA0;c2->'$.ename',json_extract(c2,&#xA0;"$.ename"),json_unquote(c2->'$.ename'),c2->>'$.ename'&#xA0;from&#xA0;t;<br>+---------------+-----------------------------+-----------------------------+----------------+<br>|&#xA0;c2->'$.ename'&#xA0;|&#xA0;json_extract(c2,&#xA0;"$.ename")&#xA0;|&#xA0;json_unquote(c2->'$.ename')&#xA0;|&#xA0;c2->>'$.ename'&#xA0;|<br>+---------------+-----------------------------+-----------------------------+----------------+<br>|&#xA0;"jack"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;"jack"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;jack&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;jack&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>|&#xA0;"mark"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;"mark"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;mark&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;mark&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------+-----------------------------+-----------------------------+----------------+<br>2&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

2.3 修改操作

JSON_INSERT(json_doc, path, val[, path, val] …)

插入新值。

仅当指定位置或指定 KEY 的值不存在时,才执行插入操作。另外,如果指定的 path 是数组下标,且 json_doc 不是数组,该函数首先会将 json_doc 转化为数组,然后再插入新值。

下面我们看几个示例。

mysql>&#xA0;select&#xA0;json_insert('1','$[0]',"10");<br>+------------------------------+<br>|&#xA0;json_insert('1','$[0]',"10")&#xA0;|<br>+------------------------------+<br>|&#xA0;1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_insert('1','$[1]',"10");<br>+------------------------------+<br>|&#xA0;json_insert('1','$[1]',"10")&#xA0;|<br>+------------------------------+<br>|&#xA0;[1,&#xA0;"10"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.01&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_insert('["1","2"]','$[2]',"10");<br>+--------------------------------------+<br>|&#xA0;json_insert('["1","2"]','$[2]',"10")&#xA0;|<br>+--------------------------------------+<br>|&#xA0;["1",&#xA0;"2",&#xA0;"10"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'{&#xA0;"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3]}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_insert(@j,&#xA0;'$.a',&#xA0;10,&#xA0;'$.c',&#xA0;'[true,&#xA0;false]');<br>+----------------------------------------------------+<br>|&#xA0;json_insert(@j,&#xA0;'$.a',&#xA0;10,&#xA0;'$.c',&#xA0;'[true,&#xA0;false]')&#xA0;|<br>+----------------------------------------------------+<br>|&#xA0;{"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3],&#xA0;"c":&#xA0;"[true,&#xA0;false]"}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+----------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_SET(json_doc, path, val[, path, val] …)

插入新值并替换已存在的值。

[En]

Insert a new value and replace the one that already exists.

换言之,如果指定位置或指定 KEY 的值不存在,会执行插入操作,如果存在,则执行更新操作。

mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'{&#xA0;"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3]}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_set(@j,&#xA0;'$.a',&#xA0;10,&#xA0;'$.c',&#xA0;'[true,&#xA0;false]');<br>+-------------------------------------------------+<br>|&#xA0;json_set(@j,&#xA0;'$.a',&#xA0;10,&#xA0;'$.c',&#xA0;'[true,&#xA0;false]')&#xA0;|<br>+-------------------------------------------------+<br>|&#xA0;{"a":&#xA0;10,&#xA0;"b":&#xA0;[2,&#xA0;3],&#xA0;"c":&#xA0;"[true,&#xA0;false]"}&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_REPLACE(json_doc, path, val[, path, val] …)

替换已经存在的值。

mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'{&#xA0;"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3]}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_replace(@j,&#xA0;'$.a',&#xA0;10,&#xA0;'$.c',&#xA0;'[true,&#xA0;false]');<br>+-----------------------------------------------------+<br>|&#xA0;json_replace(@j,&#xA0;'$.a',&#xA0;10,&#xA0;'$.c',&#xA0;'[true,&#xA0;false]')&#xA0;|<br>+-----------------------------------------------------+<br>|&#xA0;{"a":&#xA0;10,&#xA0;"b":&#xA0;[2,&#xA0;3]}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-----------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

2.4 删除操作

JSON_REMOVE(json_doc, path[, path] …)

删除 JSON 文档指定位置的元素。

mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'{&#xA0;"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3]}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_remove(@j,&#xA0;'$.a');<br>+------------------------+<br>|&#xA0;JSON_REMOVE(@j,&#xA0;'$.a')&#xA0;|<br>+------------------------+<br>|&#xA0;{"b":&#xA0;[2,&#xA0;3]}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'["a",&#xA0;["b",&#xA0;"c"],&#xA0;"d",&#xA0;"e"]';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_remove(@j,&#xA0;'$[1]');<br>+-------------------------+<br>|&#xA0;JSON_REMOVE(@j,&#xA0;'$[1]')&#xA0;|<br>+-------------------------+<br>|&#xA0;["a",&#xA0;"d",&#xA0;"e"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_remove(@j,&#xA0;'$[1]','$[2]');<br>+--------------------------------+<br>|&#xA0;JSON_REMOVE(@j,&#xA0;'$[1]','$[2]')&#xA0;|<br>+--------------------------------+<br>|&#xA0;["a",&#xA0;"d"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_remove(@j,&#xA0;'$[1]','$[1]');<br>+--------------------------------+<br>|&#xA0;JSON_REMOVE(@j,&#xA0;'$[1]','$[1]')&#xA0;|<br>+--------------------------------+<br>|&#xA0;["a",&#xA0;"e"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

最后一个查询,虽然两个 path 都是 ‘$[1]’ ,但作用对象不一样,第一个 path 的作用对象是 ‘[“a”, [“b”, “c”], “d”, “e”]’ ,第二个 path 的作用对象是删除了 ‘$[1]’ 后的数组,即 ‘[“a”, “d”, “e”]’ 。

三、如何对 JSON 字段创建索引

同 TEXT,BLOB 字段一样,JSON 字段不允许直接创建索引。

mysql>&#xA0;create&#xA0;table&#xA0;t(c1&#xA0;json,&#xA0;index&#xA0;(c1));<br>ERROR&#xA0;3152&#xA0;(42000):&#xA0;JSON&#xA0;column&#xA0;'c1'&#xA0;supports&#xA0;indexing&#xA0;only&#xA0;via&#xA0;generated&#xA0;columns&#xA0;on&#xA0;a&#xA0;specified&#xA0;JSON&#xA0;path.

即使支持,实际意义也不大,因为我们一般是基于文档中的元素进行查询,很少会基于整个 JSON 文档。

对文档中的元素进行查询,就需要用到 MySQL 5.7 引入的虚拟列及函数索引。

让我们来看一个具体的例子。

[En]

Let’s take a look at a concrete example.

#&#xA0;C2&#xA0;&#x5373;&#x865A;&#x62DF;&#x5217;<br># index (c2)&#xA0;&#x5BF9;&#x865A;&#x62DF;&#x5217;&#x6DFB;&#x52A0;&#x7D22;&#x5F15;&#x3002;<br>create&#xA0;table&#xA0;t&#xA0;(&#xA0;c1&#xA0;json,&#xA0;c2&#xA0;varchar(10)&#xA0;as&#xA0;(JSON_UNQUOTE(c1&#xA0;->&#xA0;"$.name")),&#xA0;index&#xA0;(c2)&#xA0;);<br><br>insert&#xA0;into&#xA0;t&#xA0;(c1)&#xA0;values&#xA0;&#xA0;('{"id":&#xA0;1,&#xA0;"name":&#xA0;"a"}'),&#xA0;('{"id":&#xA0;2,&#xA0;"name":&#xA0;"b"}'),&#xA0;('{"id":&#xA0;3,&#xA0;"name":&#xA0;"c"}'),&#xA0;('{"id":&#xA0;4,&#xA0;"name":&#xA0;"d"}');<br><br>mysql>&#xA0;explain&#xA0;select&#xA0;*&#xA0;from&#xA0;t&#xA0;where&#xA0;c2&#xA0;=&#xA0;'a';<br>+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+<br>|&#xA0;id&#xA0;|&#xA0;select_type&#xA0;|&#xA0;table&#xA0;|&#xA0;partitions&#xA0;|&#xA0;type&#xA0;|&#xA0;possible_keys&#xA0;|&#xA0;key&#xA0;&#xA0;|&#xA0;key_len&#xA0;|&#xA0;ref&#xA0;&#xA0;&#xA0;|&#xA0;rows&#xA0;|&#xA0;filtered&#xA0;|&#xA0;Extra&#xA0;|<br>+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+<br>|&#xA0;&#xA0;1&#xA0;|&#xA0;SIMPLE&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;t&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;NULL&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;ref&#xA0;&#xA0;|&#xA0;c2&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;c2&#xA0;&#xA0;&#xA0;|&#xA0;43&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;const&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;100.00&#xA0;|&#xA0;NULL&#xA0;&#xA0;|<br>+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+<br>1&#xA0;row&#xA0;in&#xA0;set,&#xA0;1&#xA0;warning&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;explain&#xA0;select&#xA0;*&#xA0;from&#xA0;t&#xA0;where&#xA0;c1->'$.name'&#xA0;=&#xA0;'a';<br>+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+<br>|&#xA0;id&#xA0;|&#xA0;select_type&#xA0;|&#xA0;table&#xA0;|&#xA0;partitions&#xA0;|&#xA0;type&#xA0;|&#xA0;possible_keys&#xA0;|&#xA0;key&#xA0;&#xA0;|&#xA0;key_len&#xA0;|&#xA0;ref&#xA0;&#xA0;&#xA0;|&#xA0;rows&#xA0;|&#xA0;filtered&#xA0;|&#xA0;Extra&#xA0;|<br>+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+<br>|&#xA0;&#xA0;1&#xA0;|&#xA0;SIMPLE&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;t&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;NULL&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;ref&#xA0;&#xA0;|&#xA0;c2&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;c2&#xA0;&#xA0;&#xA0;|&#xA0;43&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;const&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;100.00&#xA0;|&#xA0;NULL&#xA0;&#xA0;|<br>+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+<br>1&#xA0;row&#xA0;in&#xA0;set,&#xA0;1&#xA0;warning&#xA0;(0.00&#xA0;sec)

如您所见,无论您在文档中使用虚拟列还是元素进行查询,都可以利用较高的索引。

[En]

As you can see, whether you use virtual columns or elements in the document to query, you can take advantage of the upper index.

注意,在创建虚拟列时需指定 JSON_UNQUOTE,将 c1 -> “$.name” 的返回值转换为字符串。

四、如何将存储 JSON 字符串的字符字段升级为 JSON 字段

在 MySQL 支持 JSON 类型之前,对于 JSON 文档,一般是以字符串的形式存储在字符类型(VARCHAR 或 TEXT)中。

在 JSON 类型出来之后,如何将这些字符字段升级为 JSON 字段呢?

出于演示目的,我们首先构建测试数据。

[En]

For demonstration purposes, let’s first build the test data.

create&#xA0;table&#xA0;t&#xA0;(id&#xA0;int&#xA0;auto_increment&#xA0;primary&#xA0;key,&#xA0;c1&#xA0;text);<br><br>insert&#xA0;into&#xA0;t&#xA0;(c1)&#xA0;values&#xA0;('{"id":&#xA0;"1",&#xA0;"name":&#xA0;"a"}'),&#xA0;('{"id":&#xA0;"2",&#xA0;"name":&#xA0;"b"}'),&#xA0;('{"id":&#xA0;"3",&#xA0;"name":&#xA0;"c"}'),&#xA0;('{"id",&#xA0;"name":&#xA0;"d"}');

注意,最后一个文档有问题,不是合格的 JSON 文档。

如果使用 DDL 直接修改字段的数据类型,会报错。

mysql>&#xA0;alter&#xA0;table&#xA0;t&#xA0;modify&#xA0;c1&#xA0;json;<br>ERROR&#xA0;3140&#xA0;(22032):&#xA0;Invalid&#xA0;JSON&#xA0;text:&#xA0;"Missing&#xA0;a&#xA0;colon&#xA0;after&#xA0;a&#xA0;name&#xA0;of&#xA0;object&#xA0;member."&#xA0;at&#xA0;position&#xA0;5&#xA0;in&#xA0;value&#xA0;for&#xA0;column&#xA0;'#sql-7e1c_1f6.c1'.

接下来,我们来看看具体的升级步骤。

[En]

Next, let’s look at the specific upgrade steps.

(1)使用 json_valid 函数找出不满足 JSON 格式要求的文档。

mysql>&#xA0;select&#xA0;*&#xA0;from&#xA0;t&#xA0;where&#xA0;json_valid(c1)&#xA0;=&#xA0;0;<br>+----+---------------------+<br>|&#xA0;id&#xA0;|&#xA0;c1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+----+---------------------+<br>|&#xA0;&#xA0;4&#xA0;|&#xA0;{"id",&#xA0;"name":&#xA0;"d"}&#xA0;|<br>+----+---------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

(2)处理不满足 JSON 格式要求的文档。

mysql>&#xA0;update&#xA0;t&#xA0;set&#xA0;c1='{"id":&#xA0;"4",&#xA0;"name":&#xA0;"d"}'&#xA0;where&#xA0;id=4;<br>Query&#xA0;OK,&#xA0;1&#xA0;row&#xA0;affected&#xA0;(0.01&#xA0;sec)<br>Rows&#xA0;matched:&#xA0;1&#xA0;&#xA0;Changed:&#xA0;1&#xA0;&#xA0;Warnings:&#xA0;0

(3)将 TEXT 字段修改为 JSON 字段。

mysql>&#xA0;select&#xA0;*&#xA0;from&#xA0;t&#xA0;where&#xA0;json_valid(c1)&#xA0;=&#xA0;0;<br>Empty&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;alter&#xA0;table&#xA0;t&#xA0;modify&#xA0;c1&#xA0;json;<br>Query&#xA0;OK,&#xA0;4&#xA0;rows&#xA0;affected&#xA0;(0.13&#xA0;sec)<br>Records:&#xA0;4&#xA0;&#xA0;Duplicates:&#xA0;0&#xA0;&#xA0;Warnings:&#xA0;0

五、使用 JSON 时的注意事项

对于 JSON 类型,有以下几点需要注意:

  1. 在 MySQL 8.0.13 之前,不允许对 BLOB,TEXT,GEOMETRY,JSON 字段设置默认值。从 MySQL 8.0.13 开始,取消了这个限制。 设置时,注意默认值需通过小括号 ()括起来,否则的话,还是会提示 JSON 字段不允许设置默认值。
mysql>&#xA0;create&#xA0;table&#xA0;t(c1&#xA0;json&#xA0;not&#xA0;null&#xA0;default&#xA0;(''));<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.03&#xA0;sec)<br><br>mysql>&#xA0;create&#xA0;table&#xA0;t(c1&#xA0;json&#xA0;not&#xA0;null&#xA0;default&#xA0;'');<br>ERROR&#xA0;1101&#xA0;(42000):&#xA0;BLOB,&#xA0;TEXT,&#xA0;GEOMETRY&#xA0;or&#xA0;JSON&#xA0;column&#xA0;'c1'&#xA0;can't&#xA0;have&#xA0;a&#xA0;default&#xA0;value
  1. 不允许直接创建索引,可创建函数索引。
  2. JSON 列的最大大小和 LONGBLOB(LONGTEXT)一样,都是 4G。
  3. 插入时,单个文档的大小受到 max_allowed_packet 的限制,该参数最大是 1G。

六、Partial Updates

在 MySQL 5.7 中,对 JSON 文档进行更新,其处理策略是,删除旧的文档,再插入新的文档。即使这个修改很微小,只涉及几个字节,也会替换掉整个文档。很显然,这种处理方式的效率较为低下。

在 MySQL 8.0 中,针对 JSON 文档,引入了一项新的特性-Partial Updates(部分更新),支持 JSON 文档的原地更新。得益于这个特性,JSON 文档的处理性能得到了极大提升。

下面我们具体来看看。

6.1 使用 Partial Updates 的条件

为便于说明,此处构建了测试数据。

[En]

For ease of illustration, the test data is constructed here.

create&#xA0;table&#xA0;t&#xA0;(id&#xA0;int&#xA0;auto_increment&#xA0;primary&#xA0;key,&#xA0;c1&#xA0;json);<br><br>insert&#xA0;into&#xA0;t&#xA0;(c1)&#xA0;values&#xA0;&#xA0;('{"id":&#xA0;1,&#xA0;"name":&#xA0;"a"}'),&#xA0;('{"id":&#xA0;2,&#xA0;"name":&#xA0;"b"}'),&#xA0;('{"id":&#xA0;3,&#xA0;"name":&#xA0;"c"}'),&#xA0;('{"id":&#xA0;4,&#xA0;"name":&#xA0;"d"}');<br><br>mysql>&#xA0;select&#xA0;*&#xA0;from&#xA0;t;<br>+----+------------------------+<br>|&#xA0;id&#xA0;|&#xA0;c1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+----+------------------------+<br>|&#xA0;&#xA0;1&#xA0;|&#xA0;{"id":&#xA0;1,&#xA0;"name":&#xA0;"a"}&#xA0;|<br>|&#xA0;&#xA0;2&#xA0;|&#xA0;{"id":&#xA0;2,&#xA0;"name":&#xA0;"b"}&#xA0;|<br>|&#xA0;&#xA0;3&#xA0;|&#xA0;{"id":&#xA0;3,&#xA0;"name":&#xA0;"c"}&#xA0;|<br>|&#xA0;&#xA0;4&#xA0;|&#xA0;{"id":&#xA0;4,&#xA0;"name":&#xA0;"d"}&#xA0;|<br>+----+------------------------+<br>4&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

使用 Partial Updates 需满足以下条件:

  1. 被更新的列是 JSON 类型。
  2. 使用 JSON_SET,JSON_REPLACE,JSON_REMOVE 进行 UPDATE 操作,如,
update&#xA0;t&#xA0;set&#xA0;c1=json_remove(c1,'$.id')&#xA0;where&#xA0;id=1;

如果不使用这三个函数并显式赋值,则不会进行部分更新,例如

[En]

If you do not use these three functions and assign values explicitly, there will be no partial updates, such as

update&#xA0;t&#xA0;set&#xA0;c1='{"id":&#xA0;1,&#xA0;"name":&#xA0;"a"}'&#xA0;where&#xA0;id=1;
  1. 输入列和目标列必须是同一列,如,
update&#xA0;t&#xA0;set&#xA0;c1=json_replace(c1,'$.id',10)&#xA0;where&#xA0;id=1;

否则,将不会进行部分更新,例如

[En]

Otherwise, partial updates will not be made, such as

update&#xA0;t&#xA0;set&#xA0;c1=json_replace(c2,'$.id',10)&#xA0;where&#xA0;id=1;
  1. 变更前后,JSON 文档的空间使用不会增加。

对于最后一个条件,让我们看一下下面的示例。

[En]

For the last condition, let’s take a look at the following example.

mysql>&#xA0;select&#xA0;*,json_storage_size(c1),json_storage_free(c1)&#xA0;from&#xA0;t&#xA0;where&#xA0;id=1;<br>+----+------------------------+-----------------------+-----------------------+<br>|&#xA0;id&#xA0;|&#xA0;c1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;json_storage_size(c1)&#xA0;|&#xA0;json_storage_free(c1)&#xA0;|<br>+----+------------------------+-----------------------+-----------------------+<br>|&#xA0;&#xA0;1&#xA0;|&#xA0;{"id":&#xA0;1,&#xA0;"name":&#xA0;"a"}&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;27&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+----+------------------------+-----------------------+-----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;update&#xA0;t&#xA0;set&#xA0;c1=json_remove(c1,'$.id')&#xA0;where&#xA0;id=1;<br>Query&#xA0;OK,&#xA0;1&#xA0;row&#xA0;affected&#xA0;(0.01&#xA0;sec)<br>Rows&#xA0;matched:&#xA0;1&#xA0;&#xA0;Changed:&#xA0;1&#xA0;&#xA0;Warnings:&#xA0;0<br><br>mysql>&#xA0;select&#xA0;*,json_storage_size(c1),json_storage_free(c1)&#xA0;from&#xA0;t&#xA0;where&#xA0;id=1;<br>+----+---------------+-----------------------+-----------------------+<br>|&#xA0;id&#xA0;|&#xA0;c1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;json_storage_size(c1)&#xA0;|&#xA0;json_storage_free(c1)&#xA0;|<br>+----+---------------+-----------------------+-----------------------+<br>|&#xA0;&#xA0;1&#xA0;|&#xA0;{"name":&#xA0;"a"}&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;27&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;9&#xA0;|<br>+----+---------------+-----------------------+-----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;update&#xA0;t&#xA0;set&#xA0;c1=json_set(c1,'$.id',3306)&#xA0;where&#xA0;id=1;<br>Query&#xA0;OK,&#xA0;1&#xA0;row&#xA0;affected&#xA0;(0.01&#xA0;sec)<br>Rows&#xA0;matched:&#xA0;1&#xA0;&#xA0;Changed:&#xA0;1&#xA0;&#xA0;Warnings:&#xA0;0<br><br>mysql>&#xA0;select&#xA0;*,json_storage_size(c1),json_storage_free(c1)&#xA0;from&#xA0;t&#xA0;where&#xA0;id=1;<br>+----+---------------------------+-----------------------+-----------------------+<br>|&#xA0;id&#xA0;|&#xA0;c1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;json_storage_size(c1)&#xA0;|&#xA0;json_storage_free(c1)&#xA0;|<br>+----+---------------------------+-----------------------+-----------------------+<br>|&#xA0;&#xA0;1&#xA0;|&#xA0;{"id":&#xA0;3306,&#xA0;"name":&#xA0;"a"}&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;27&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+----+---------------------------+-----------------------+-----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;update&#xA0;t&#xA0;set&#xA0;c1=json_set(c1,'$.id','mysql')&#xA0;where&#xA0;id=1;<br>Query&#xA0;OK,&#xA0;1&#xA0;row&#xA0;affected&#xA0;(0.01&#xA0;sec)<br>Rows&#xA0;matched:&#xA0;1&#xA0;&#xA0;Changed:&#xA0;1&#xA0;&#xA0;Warnings:&#xA0;0<br><br>mysql>&#xA0;select&#xA0;*,json_storage_size(c1),json_storage_free(c1)&#xA0;from&#xA0;t&#xA0;where&#xA0;id=1;<br>+----+------------------------------+-----------------------+-----------------------+<br>|&#xA0;id&#xA0;|&#xA0;c1&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;json_storage_size(c1)&#xA0;|&#xA0;json_storage_free(c1)&#xA0;|<br>+----+------------------------------+-----------------------+-----------------------+<br>|&#xA0;&#xA0;1&#xA0;|&#xA0;{"id":&#xA0;"mysql",&#xA0;"name":&#xA0;"a"}&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;33&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+----+------------------------------+-----------------------+-----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

示例中,用到了两个函数:JSON_STORAGE_SIZE 和 JSON_STORAGE_FREE ,前者用来获取 JSON 文档的空间使用情况,后者用来获取 JSON 文档在执行原地更新后的空间释放情况。

这里一共执行了三次 UPDATE 操作,前两次是原地更新,第三次不是。同样是 JSON_SET 操作,为什么第一次是原地更新,而第二次不是呢?

因为第一次的 JSON_SET 复用了 JSON_REMOVE 释放的空间。而第二次的 JSON_SET 执行的是更新操作,且 ‘mysql’ 比 3306 需要更多的存储空间。

6.2 如何在 binlog 中开启 Partial Updates

Partial Updates 不仅仅适用于存储引擎层,还可用于主从复制场景。

主从复制开启 Partial Updates,只需将参数 binlog_row_value_options(默认为空)设置为 PARTIAL_JSON。

下面具体来看看,同一个 UPDATE 操作,开启和不开启 Partial Updates,在 binlog 中的记录有何区别。

update&#xA0;t&#xA0;set&#xA0;c1=json_replace(c1,'$.id',10)&#xA0;where&#xA0;id=1;

不开启

###&#xA0;UPDATE&#xA0;slowtech.t<br>###&#xA0;WHERE<br>###&#xA0;&#xA0;&#xA0;@1=1<br>###&#xA0;&#xA0;&#xA0;@2='{"id":&#xA0;"1",&#xA0;"name":&#xA0;"a"}'<br>###&#xA0;SET<br>###&#xA0;&#xA0;&#xA0;@1=1<br>###&#xA0;&#xA0;&#xA0;@2='{"id":&#xA0;10,&#xA0;"name":&#xA0;"a"}'

开启

###&#xA0;UPDATE&#xA0;slowtech.t<br>###&#xA0;WHERE<br>###&#xA0;&#xA0;&#xA0;@1=1<br>###&#xA0;&#xA0;&#xA0;@2='{"id":&#xA0;1,&#xA0;"name":&#xA0;"a"}'<br>###&#xA0;SET<br>###&#xA0;&#xA0;&#xA0;@1=1<br>###&#xA0;&#xA0;&#xA0;@2=JSON_REPLACE(@2,&#xA0;'$.id',&#xA0;10)

对比 binlog 的内容,可以看到,不开启,无论是修改前的镜像(before_image)还是修改后的镜像(after_image),记录的都是完整文档。而开启后,对于修改后的镜像,记录的是命令,而不是完整文档,这样可节省近一半的空间。

在将 binlog_row_value_options 设置为 PARTIAL_JSON 后,对于可使用 Partial Updates 的操作,在 binlog 中,不再通过 ROWS_EVENT 来记录,而是新增了一个 PARTIAL_UPDATE_ROWS_EVENT 的事件类型。

需要注意的是,binlog 中使用 Partial Updates,只需满足存储引擎层使用 Partial Updates 的前三个条件,无需考虑变更前后,JSON 文档的空间使用是否会增加。

6.3 关于 Partial Updates 的性能测试

首先构造测试数据,t 表一共有 16 个文档,每个文档近 10 MB。

create&#xA0;table&#xA0;t(id&#xA0;int&#xA0;auto_increment&#xA0;primary&#xA0;key,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;json_col&#xA0;json,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;name&#xA0;varchar(100)&#xA0;as&#xA0;(json_col->>'$.name'),<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;age&#xA0;int&#xA0;as&#xA0;(json_col->'$.age'));<br><br>insert&#xA0;into&#xA0;t(json_col)&#xA0;values<br>(json_object('name',&#xA0;'Joe',&#xA0;'age',&#xA0;24,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;'data',&#xA0;repeat('x',&#xA0;10&#xA0;*&#xA0;1000&#xA0;*&#xA0;1000))),<br>(json_object('name',&#xA0;'Sue',&#xA0;'age',&#xA0;32,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;'data',&#xA0;repeat('y',&#xA0;10&#xA0;*&#xA0;1000&#xA0;*&#xA0;1000))),<br>(json_object('name',&#xA0;'Pete',&#xA0;'age',&#xA0;40,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;'data',&#xA0;repeat('z',&#xA0;10&#xA0;*&#xA0;1000&#xA0;*&#xA0;1000))),<br>(json_object('name',&#xA0;'Jenny',&#xA0;'age',&#xA0;27,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;'data',&#xA0;repeat('w',&#xA0;10&#xA0;*&#xA0;1000&#xA0;*&#xA0;1000)));<br><br>insert&#xA0;into&#xA0;t(json_col)&#xA0;select&#xA0;json_col&#xA0;from&#xA0;t;<br>insert&#xA0;into&#xA0;t(json_col)&#xA0;select&#xA0;json_col&#xA0;from&#xA0;t;

接下来,测试下述 SQL

update&#xA0;t&#xA0;set&#xA0;json_col&#xA0;=&#xA0;json_set(json_col,&#xA0;'$.age',&#xA0;age&#xA0;+&#xA0;1);

以下四种场景的执行时间:

[En]

Execution time in the following four scenarios:

  1. MySQL 5.7.36
  2. MySQL 8.0.27
  3. MySQL 8.0.27,binlog_row_value_options=PARTIAL_JSON
  4. MySQL 8.0.27,binlog_row_value_options=PARTIAL_JSON + binlog_row_image=MINIMAL

分别执行 10 次,去掉最大值和最小值后求平均值。

最后的测试结果如下

一文说透 MySQL JSON 数据类型(收藏)

以 MySQL 5.7.36 的查询时间作为基准:

  1. MySQL 8.0 只开启存储引擎层的 Partial Updates,查询时间比 MySQL 5.7 快 1.94 倍。
  2. MySQL 8.0 同时开启存储引擎层和 binlog 中的 Partial Updates,查询时间比 MySQL 5.7 快 4.87 倍。
  3. 如果在 2 的基础上,同时将 binlog_row_image 设置为 MINIMAL,查询时间更是比 MySQL 5.7 快 102.22 倍。

当然,在生产环境,我们一般很少将 binlog_row_image 设置为 MINIMAL。

但即使如此,只开启存储引擎层和 binlog 中的 Partial Updates,查询时间也比 MySQL 5.7 快 4.87 倍,性能提升还是比较明显的。

七、其它 JSON 函数

7.1 查询相关

JSON_CONTAINS(target, candidate[, path])

判断 target 文档是否包含 candidate 文档,如果包含,则返回 1,否则是 0。

mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'{"a":&#xA0;[1,&#xA0;2],&#xA0;"b":&#xA0;3,&#xA0;"c":&#xA0;{"d":&#xA0;4}}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_contains(@j,&#xA0;'1',&#xA0;'$.a'),json_contains(@j,&#xA0;'1',&#xA0;'$.b');<br>+-------------------------------+-------------------------------+<br>|&#xA0;json_contains(@j,&#xA0;'1',&#xA0;'$.a')&#xA0;|&#xA0;json_contains(@j,&#xA0;'1',&#xA0;'$.b')&#xA0;|<br>+-------------------------------+-------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+-------------------------------+-------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_contains(@j,'{"d":&#xA0;4}','$.a'),json_contains(@j,'{"d":&#xA0;4}','$.c');<br>+------------------------------------+------------------------------------+<br>|&#xA0;json_contains(@j,'{"d":&#xA0;4}','$.a')&#xA0;|&#xA0;json_contains(@j,'{"d":&#xA0;4}','$.c')&#xA0;|<br>+------------------------------------+------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+------------------------------------+------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] …)

判断指定的 path 是否存在,存在,则返回 1,否则是 0。

函数中的 one_or_all 可指定 one 或 all,one 是任意一个路径存在就返回 1,all 是所有路径都存在才返回 1。

mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'{"a":&#xA0;[1,&#xA0;2],&#xA0;"b":&#xA0;3,&#xA0;"c":&#xA0;{"d":&#xA0;4}}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_contains_path(@j,&#xA0;'one',&#xA0;'$.a',&#xA0;'$.e'),&#xA0;json_contains_path(@j,&#xA0;'all',&#xA0;'$.a',&#xA0;'$.e');<br>+---------------------------------------------+---------------------------------------------+<br>|&#xA0;json_contains_path(@j,&#xA0;'one',&#xA0;'$.a',&#xA0;'$.e')&#xA0;|&#xA0;json_contains_path(@j,&#xA0;'all',&#xA0;'$.a',&#xA0;'$.e')&#xA0;|<br>+---------------------------------------------+---------------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+---------------------------------------------+---------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_contains_path(@j,&#xA0;'one',&#xA0;'$.c.d'),json_contains_path(@j,&#xA0;'one',&#xA0;'$.a.d');<br>+----------------------------------------+----------------------------------------+<br>|&#xA0;json_contains_path(@j,&#xA0;'one',&#xA0;'$.c.d')&#xA0;|&#xA0;json_contains_path(@j,&#xA0;'one',&#xA0;'$.a.d')&#xA0;|<br>+----------------------------------------+----------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+----------------------------------------+----------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_SEARCH(json_doc, one_or_all, search_str[, escape_char[, path] …])

返回某个字符串(search_str)在 JSON 文档中的位置,其中,

  • one_or_all:匹配的次数,one 是只匹配一次,all 是匹配所有。如果匹配到多个,结果会以数组的形式返回。
  • search_str:子串,支持模糊匹配: %&#xA0;_
  • escape_char:转义符,如果该参数不填或为 NULL,则取默认转义符 \
  • path:查找路径。
mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'["abc",&#xA0;[{"k":&#xA0;"10"},&#xA0;"def"],&#xA0;{"x":"abc"},&#xA0;{"y":"bcd"}]';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_search(@j,&#xA0;'one',&#xA0;'abc'),json_search(@j,&#xA0;'all',&#xA0;'abc'),json_search(@j,&#xA0;'all',&#xA0;'ghi');<br>+-------------------------------+-------------------------------+-------------------------------+<br>|&#xA0;json_search(@j,&#xA0;'one',&#xA0;'abc')&#xA0;|&#xA0;json_search(@j,&#xA0;'all',&#xA0;'abc')&#xA0;|&#xA0;json_search(@j,&#xA0;'all',&#xA0;'ghi')&#xA0;|<br>+-------------------------------+-------------------------------+-------------------------------+<br>|&#xA0;"$[0]"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;["$[0]",&#xA0;"$[2].x"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;NULL&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-------------------------------+-------------------------------+-------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_search(@j,&#xA0;'all',&#xA0;'%b%',&#xA0;NULL,&#xA0;'$[1]'),&#xA0;json_search(@j,&#xA0;'all',&#xA0;'%b%',&#xA0;NULL,&#xA0;'$[3]');<br>+---------------------------------------------+---------------------------------------------+<br>|&#xA0;json_search(@j,&#xA0;'all',&#xA0;'%b%',&#xA0;NULL,&#xA0;'$[1]')&#xA0;|&#xA0;json_search(@j,&#xA0;'all',&#xA0;'%b%',&#xA0;NULL,&#xA0;'$[3]')&#xA0;|<br>+---------------------------------------------+---------------------------------------------+<br>|&#xA0;NULL&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;"$[3].y"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------+---------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_KEYS(json_doc[, path])

返回 JSON 文档最外层的 key,如果指定了 path,则返回该 path 对应元素最外层的 key。

mysql>&#xA0;select&#xA0;json_keys('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}');<br>+---------------------------------------+<br>|&#xA0;json_keys('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}')&#xA0;|<br>+---------------------------------------+<br>|&#xA0;["a",&#xA0;"b"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_keys('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}',&#xA0;'$.b');<br>+----------------------------------------------+<br>|&#xA0;json_keys('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}',&#xA0;'$.b')&#xA0;|<br>+----------------------------------------------+<br>|&#xA0;["c"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+----------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_VALUE(json_doc, path)

8.0.21 引入的,从 JSON 文档提取指定路径(path)的元素。

该函数的完整语法如下:

JSON_VALUE(json_doc,&#xA0;path&#xA0;[RETURNING&#xA0;type]&#xA0;[on_empty]&#xA0;[on_error])<br><br>on_empty:<br>&#xA0;&#xA0;&#xA0;&#xA0;{NULL&#xA0;|&#xA0;ERROR&#xA0;|&#xA0;DEFAULT&#xA0;value}&#xA0;ON&#xA0;EMPTY<br><br>on_error:<br>&#xA0;&#xA0;&#xA0;&#xA0;{NULL&#xA0;|&#xA0;ERROR&#xA0;|&#xA0;DEFAULT&#xA0;value}&#xA0;ON&#xA0;ERROR

其中:

  • RETURNING type:返回值的类型,不指定,则默认是 VARCHAR(512)。不指定字符集,则默认是 utf8mb4,且区分大小写。
  • on_empty:如果指定路径没有值,会触发 on_empty 子句, 默认是返回 NULL,也可指定 ERROR 抛出错误,或者通过 DEFAULT value 返回默认值。
  • on_error:三种情况下会触发 on_error 子句:从数组或对象中提取元素时,会解析到多个值;类型转换错误,譬如将 “abc” 转换为 unsigned 类型;值被 truncate 了。默认是返回 NULL。
mysql>&#xA0;select&#xA0;json_value('{"item":&#xA0;"shoes",&#xA0;"price":&#xA0;"49.95"}',&#xA0;'$.item');<br>+-------------------------------------------------------------+<br>|&#xA0;json_value('{"item":&#xA0;"shoes",&#xA0;"price":&#xA0;"49.95"}',&#xA0;'$.item')&#xA0;|<br>+-------------------------------------------------------------+<br>|&#xA0;shoes&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-------------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_value('{"item":&#xA0;"shoes",&#xA0;"price":&#xA0;"49.95"}',&#xA0;'$.price'&#xA0;returning&#xA0;decimal(4,2))&#xA0;as&#xA0;price;<br>+-------+<br>|&#xA0;price&#xA0;|<br>+-------+<br>|&#xA0;49.95&#xA0;|<br>+-------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_value('{"item":&#xA0;"shoes",&#xA0;"price":&#xA0;"49.95"}',&#xA0;'$.price1'&#xA0;error&#xA0;on&#xA0;empty);<br>ERROR&#xA0;3966&#xA0;(22035):&#xA0;No&#xA0;value&#xA0;was&#xA0;found&#xA0;by&#xA0;'json_value'&#xA0;on&#xA0;the&#xA0;specified&#xA0;path.<br><br>mysql>&#xA0;select&#xA0;json_value('[1,&#xA0;2,&#xA0;3]',&#xA0;'$[1&#xA0;to&#xA0;2]'&#xA0;error&#xA0;on&#xA0;error);<br>ERROR&#xA0;3967&#xA0;(22034):&#xA0;More&#xA0;than&#xA0;one&#xA0;value&#xA0;was&#xA0;found&#xA0;by&#xA0;'json_value'&#xA0;on&#xA0;the&#xA0;specified&#xA0;path.<br><br>mysql>&#xA0;select&#xA0;json_value('{"item":&#xA0;"shoes",&#xA0;"price":&#xA0;"49.95"}',&#xA0;'$.item'&#xA0;returning&#xA0;unsigned&#xA0;error&#xA0;on&#xA0;error)&#xA0;as&#xA0;price;<br>ERROR&#xA0;1690&#xA0;(22003):&#xA0;UNSIGNED&#xA0;value&#xA0;is&#xA0;out&#xA0;of&#xA0;range&#xA0;in&#xA0;'json_value'

value MEMBER OF(json_array)

判断 value 是否是 JSON 数组的一个元素,如果是,则返回 1,否则是 0。

mysql>&#xA0;select&#xA0;17&#xA0;member&#xA0;of('[23,&#xA0;"abc",&#xA0;17,&#xA0;"ab",&#xA0;10]');<br>+-------------------------------------------+<br>|&#xA0;17&#xA0;member&#xA0;of('[23,&#xA0;"abc",&#xA0;17,&#xA0;"ab",&#xA0;10]')&#xA0;|<br>+-------------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+-------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;cast('[4,5]'&#xA0;as&#xA0;json)&#xA0;member&#xA0;of('[[3,4],[4,5]]');<br>+--------------------------------------------------+<br>|&#xA0;cast('[4,5]'&#xA0;as&#xA0;json)&#xA0;member&#xA0;of('[[3,4],[4,5]]')&#xA0;|<br>+--------------------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+--------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_OVERLAPS(json_doc1, json_doc2)

MySQL 8.0.17 引入的,用来比较两个 JSON 文档是否有相同的键值对或数组元素,如果有,则返回 1,否则是 0。如果两个参数都是标量,则判断这两个标量是否相等。

mysql>&#xA0;select&#xA0;json_overlaps('[1,3,5,7]',&#xA0;'[2,5,7]'),json_overlaps('[1,3,5,7]',&#xA0;'[2,6,8]');<br>+---------------------------------------+---------------------------------------+<br>|&#xA0;json_overlaps('[1,3,5,7]',&#xA0;'[2,5,7]')&#xA0;|&#xA0;json_overlaps('[1,3,5,7]',&#xA0;'[2,6,8]')&#xA0;|<br>+---------------------------------------+---------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+---------------------------------------+---------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_overlaps('{"a":1,"b":2}',&#xA0;'{"c":3,"d":4,"b":2}');<br>+-------------------------------------------------------+<br>|&#xA0;json_overlaps('{"a":1,"b":2}',&#xA0;'{"c":3,"d":4,"b":2}')&#xA0;|<br>+-------------------------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+-------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_overlaps('{"a":1,"b":2}',&#xA0;'{"c":3,"d":4,"b":10}');<br>+--------------------------------------------------------+<br>|&#xA0;json_overlaps('{"a":1,"b":2}',&#xA0;'{"c":3,"d":4,"b":10}')&#xA0;|<br>+--------------------------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+--------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_overlaps('5',&#xA0;'5'),json_overlaps('5',&#xA0;'6');<br>+-------------------------+-------------------------+<br>|&#xA0;json_overlaps('5',&#xA0;'5')&#xA0;|&#xA0;json_overlaps('5',&#xA0;'6')&#xA0;|<br>+-------------------------+-------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+-------------------------+-------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

从 MySQL 8.0.17 开始,InnoDB 支持多值索引,可用在 JSON 数组中。当我们使用 JSON_CONTAINS、MEMBER OF、JSON_OVERLAPS 进行数组相关的操作时,可使用多值索引来加快查询。

7.2 修改相关

JSON_ARRAY_APPEND(json_doc, path, val[, path, val] …)

向数组指定位置追加元素。如果指定 path 不存在,则不添加。

mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'["a",&#xA0;["b",&#xA0;"c"],&#xA0;"d"]';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_array_append(@j,&#xA0;'$[0]',&#xA0;1,&#xA0;'$[1][0]',&#xA0;2,&#xA0;'$[3]',&#xA0;3);<br>+-----------------------------------------------------------+<br>|&#xA0;json_array_append(@j,&#xA0;'$[0]',&#xA0;1,&#xA0;'$[1][0]',&#xA0;2,&#xA0;'$[3]',&#xA0;3)&#xA0;|<br>+-----------------------------------------------------------+<br>|&#xA0;[["a",&#xA0;1],&#xA0;[["b",&#xA0;2],&#xA0;"c"],&#xA0;"d"]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-----------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'{"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3],&#xA0;"c":&#xA0;4}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_array_append(@j,&#xA0;'$.b',&#xA0;'x',&#xA0;'$',&#xA0;'z');<br>+---------------------------------------------+<br>|&#xA0;json_array_append(@j,&#xA0;'$.b',&#xA0;'x',&#xA0;'$',&#xA0;'z')&#xA0;|<br>+---------------------------------------------+<br>|&#xA0;[{"a":&#xA0;1,&#xA0;"b":&#xA0;[2,&#xA0;3,&#xA0;"x"],&#xA0;"c":&#xA0;4},&#xA0;"z"]&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_ARRAY_INSERT(json_doc, path, val[, path, val] …)

将元素插入到数组中的指定位置。

[En]

Inserts an element into the array at the specified location.

mysql>&#xA0;set&#xA0;@j&#xA0;=&#xA0;'["a",&#xA0;["b",&#xA0;"c"],{"d":"e"}]';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_array_insert(@j,&#xA0;'$[0]',&#xA0;1);<br>+----------------------------------+<br>|&#xA0;json_array_insert(@j,&#xA0;'$[0]',&#xA0;1)&#xA0;|<br>+----------------------------------+<br>|&#xA0;[1,&#xA0;"a",&#xA0;["b",&#xA0;"c"],&#xA0;{"d":&#xA0;"e"}]&#xA0;|<br>+----------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_array_insert(@j,&#xA0;'$[1]',&#xA0;cast('[1,2]'&#xA0;as&#xA0;json));<br>+------------------------------------------------------+<br>|&#xA0;json_array_insert(@j,&#xA0;'$[1]',&#xA0;cast('[1,2]'&#xA0;as&#xA0;json))&#xA0;|<br>+------------------------------------------------------+<br>|&#xA0;["a",&#xA0;[1,&#xA0;2],&#xA0;["b",&#xA0;"c"],&#xA0;{"d":&#xA0;"e"}]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_array_insert(@j,&#xA0;'$[5]',&#xA0;2);<br>+----------------------------------+<br>|&#xA0;json_array_insert(@j,&#xA0;'$[5]',&#xA0;2)&#xA0;|<br>+----------------------------------+<br>|&#xA0;["a",&#xA0;["b",&#xA0;"c"],&#xA0;{"d":&#xA0;"e"},&#xA0;2]&#xA0;|<br>+----------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_MERGE_PATCH(json_doc, json_doc[, json_doc] …)

MySQL 8.0.3 引入的,用来合并多个 JSON 文档。其合并规则如下:

  1. 如果两个文档不全是 JSON 对象,则合并后的结果是第二个文档。
  2. 如果两个文档都是 JSON 对象,且不存在着同名 KEY,则合并后的文档包括两个文档的所有元素,如果存在着同名 KEY,则第二个文档的值会覆盖第一个。
mysql>&#xA0;select&#xA0;json_merge_patch('[1,&#xA0;2]',&#xA0;'[3,&#xA0;4]'),&#xA0;json_merge_patch('[1,&#xA0;2]',&#xA0;'{"a":&#xA0;123}');<br>+--------------------------------------+------------------------------------------+<br>|&#xA0;json_merge_patch('[1,&#xA0;2]',&#xA0;'[3,&#xA0;4]')&#xA0;|&#xA0;json_merge_patch('[1,&#xA0;2]',&#xA0;'{"a":&#xA0;123}')&#xA0;|<br>+--------------------------------------+------------------------------------------+<br>|&#xA0;[3,&#xA0;4]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;{"a":&#xA0;123}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------+------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_merge_patch('{"a":&#xA0;1}',&#xA0;'{"b":&#xA0;2}'),json_merge_patch('{&#xA0;"a":&#xA0;1,&#xA0;"b":2&#xA0;}','{&#xA0;"a":&#xA0;3,&#xA0;"c":4&#xA0;}');<br>+------------------------------------------+-----------------------------------------------------------+<br>|&#xA0;json_merge_patch('{"a":&#xA0;1}',&#xA0;'{"b":&#xA0;2}')&#xA0;|&#xA0;json_merge_patch('{&#xA0;"a":&#xA0;1,&#xA0;"b":2&#xA0;}','{&#xA0;"a":&#xA0;3,&#xA0;"c":4&#xA0;}')&#xA0;|<br>+------------------------------------------+-----------------------------------------------------------+<br>|&#xA0;{"a":&#xA0;1,&#xA0;"b":&#xA0;2}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;{"a":&#xA0;3,&#xA0;"b":&#xA0;2,&#xA0;"c":&#xA0;4}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------------------------------+-----------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>#&#xA0;&#x5982;&#x679C;&#x7B2C;&#x4E8C;&#x4E2A;&#x6587;&#x6863;&#x5B58;&#x5728; null &#x503C;&#xFF0C;&#x6587;&#x6863;&#x5408;&#x5E76;&#x540E;&#x4E0D;&#x4F1A;&#x8F93;&#x51FA;&#x5BF9;&#x5E94;&#x7684; KEY&#x3002;<br>mysql>&#xA0;select&#xA0;json_merge_patch('{"a":1,&#xA0;"b":2}',&#xA0;'{"a":3,&#xA0;"b":null}');<br>+---------------------------------------------------------+<br>|&#xA0;json_merge_patch('{"a":1,&#xA0;"b":2}',&#xA0;'{"a":3,&#xA0;"b":null}')&#xA0;|<br>+---------------------------------------------------------+<br>|&#xA0;{"a":&#xA0;3}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_MERGE_PRESERVE(json_doc, json_doc[, json_doc] …)

MySQL 8.0.3 引入的,用来代替 JSON_MERGE。也是用来合并文档,但合并规则与 JSON_MERGE_PATCH 有所不同。

  1. 两个文档中,只要有一个文档是数组,则另外一个文档会合并到该数组中。
  2. 两个文档都是 JSON 对象,若存在着同名 KEY ,第二个文档并不会覆盖第一个,而是会将值 append 到第一个文档中。
mysql>&#xA0;select&#xA0;json_merge_preserve('1','2'),json_merge_preserve('[1,&#xA0;2]',&#xA0;'[3,&#xA0;4]');<br>+------------------------------+-----------------------------------------+<br>|&#xA0;json_merge_preserve('1','2')&#xA0;|&#xA0;json_merge_preserve('[1,&#xA0;2]',&#xA0;'[3,&#xA0;4]')&#xA0;|<br>+------------------------------+-----------------------------------------+<br>|&#xA0;[1,&#xA0;2]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;[1,&#xA0;2,&#xA0;3,&#xA0;4]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------------------+-----------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_merge_preserve('[1,&#xA0;2]',&#xA0;'{"a":&#xA0;123}'),&#xA0;json_merge_preserve('{"a":&#xA0;123}',&#xA0;'[3,4]');<br>+---------------------------------------------+--------------------------------------------+<br>|&#xA0;json_merge_preserve('[1,&#xA0;2]',&#xA0;'{"a":&#xA0;123}')&#xA0;|&#xA0;json_merge_preserve('{"a":&#xA0;123}',&#xA0;'[3,4]')&#xA0;|<br>+---------------------------------------------+--------------------------------------------+<br>|&#xA0;[1,&#xA0;2,&#xA0;{"a":&#xA0;123}]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;[{"a":&#xA0;123},&#xA0;3,&#xA0;4]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------+--------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_merge_preserve('{"a":&#xA0;1}',&#xA0;'{"b":&#xA0;2}'),&#xA0;json_merge_preserve('{&#xA0;"a":&#xA0;1,&#xA0;"b":2&#xA0;}','{&#xA0;"a":&#xA0;3,&#xA0;"c":4&#xA0;}');<br>+---------------------------------------------+--------------------------------------------------------------+<br>|&#xA0;json_merge_preserve('{"a":&#xA0;1}',&#xA0;'{"b":&#xA0;2}')&#xA0;|&#xA0;json_merge_preserve('{&#xA0;"a":&#xA0;1,&#xA0;"b":2&#xA0;}','{&#xA0;"a":&#xA0;3,&#xA0;"c":4&#xA0;}')&#xA0;|<br>+---------------------------------------------+--------------------------------------------------------------+<br>|&#xA0;{"a":&#xA0;1,&#xA0;"b":&#xA0;2}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;{"a":&#xA0;[1,&#xA0;3],&#xA0;"b":&#xA0;2,&#xA0;"c":&#xA0;4}&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------+--------------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_MERGE(json_doc, json_doc[, json_doc] …)

与 JSON_MERGE_PRESERVE 作用一样,从 MySQL 8.0.3 开始不建议使用,后续会移除。

7.3 其它辅助函数

JSON_QUOTE(string)

生成有效的 JSON 字符串,主要是对一些特殊字符(如双引号)进行转义。

mysql>&#xA0;select&#xA0;json_quote('null'),&#xA0;json_quote('"null"'),&#xA0;json_quote('[1,&#xA0;2,&#xA0;3]');<br>+--------------------+----------------------+-------------------------+<br>|&#xA0;json_quote('null')&#xA0;|&#xA0;json_quote('"null"')&#xA0;|&#xA0;json_quote('[1,&#xA0;2,&#xA0;3]')&#xA0;|<br>+--------------------+----------------------+-------------------------+<br>|&#xA0;"null"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;"\"null\""&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;"[1,&#xA0;2,&#xA0;3]"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------+----------------------+-------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

除此之外,也可通过 CAST(value AS JSON) 进行类型转换。

JSON_UNQUOTE(json_val)

将 JSON 转义成字符串输出。

mysql>&#xA0;select&#xA0;c2->'$.ename',json_unquote(c2->'$.ename'),<br>&#xA0;&#xA0;&#xA0;&#xA0;->&#xA0;json_valid(c2->'$.ename'),json_valid(json_unquote(c2->'$.ename'))&#xA0;from&#xA0;t;<br>+---------------+-----------------------------+---------------------------+-----------------------------------------+<br>|&#xA0;c2->'$.ename'&#xA0;|&#xA0;json_unquote(c2->'$.ename')&#xA0;|&#xA0;json_valid(c2->'$.ename')&#xA0;|&#xA0;json_valid(json_unquote(c2->'$.ename'))&#xA0;|<br>+---------------+-----------------------------+---------------------------+-----------------------------------------+<br>|&#xA0;"jack"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;jack&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>|&#xA0;"mark"&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;mark&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+---------------+-----------------------------+---------------------------+-----------------------------------------+<br>2&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

直观地看,没加 JSON_UNQUOTE 字符串会用双引号引起来,加了 JSON_UNQUOTE 就没有。但本质上,前者是 JSON 中的 STRING 类型,后者是 MySQL 中的字符类型,这一点可通过 JSON_VALID 来判断。

JSON_OBJECTAGG(key, value)

取表中的两列作为参数,其中,第一列是 key,第二列是 value,返回 JSON 对象。如,

mysql>&#xA0;select&#xA0;*&#xA0;from&#xA0;emp;<br>+--------+----------+--------+<br>|&#xA0;deptno&#xA0;|&#xA0;ename&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;sal&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------+----------+--------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;10&#xA0;|&#xA0;emp_1001&#xA0;|&#xA0;100.00&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;10&#xA0;|&#xA0;emp_1002&#xA0;|&#xA0;200.00&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;20&#xA0;|&#xA0;emp_1003&#xA0;|&#xA0;300.00&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;20&#xA0;|&#xA0;emp_1004&#xA0;|&#xA0;400.00&#xA0;|<br>+--------+----------+--------+<br>4&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_objectagg(ename,sal)&#xA0;from&#xA0;emp;<br>+----------------------------------------------------------------------------------+<br>|&#xA0;json_objectagg(ename,sal)&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+----------------------------------------------------------------------------------+<br>|&#xA0;{"emp_1001":&#xA0;100.00,&#xA0;"emp_1002":&#xA0;200.00,&#xA0;"emp_1003":&#xA0;300.00,&#xA0;"emp_1004":&#xA0;400.00}&#xA0;|<br>+----------------------------------------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;deptno,json_objectagg(ename,sal)&#xA0;from&#xA0;emp&#xA0;group&#xA0;by&#xA0;deptno;<br>+--------+------------------------------------------+<br>|&#xA0;deptno&#xA0;|&#xA0;json_objectagg(ename,sal)&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------+------------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;10&#xA0;|&#xA0;{"emp_1001":&#xA0;100.00,&#xA0;"emp_1002":&#xA0;200.00}&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;20&#xA0;|&#xA0;{"emp_1003":&#xA0;300.00,&#xA0;"emp_1004":&#xA0;400.00}&#xA0;|<br>+--------+------------------------------------------+<br>2&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_ARRAYAGG(col_or_expr)

将列的值聚合成 JSON 数组,注意,JSON 数组中元素的顺序是随机的。

mysql>&#xA0;select&#xA0;json_arrayagg(ename)&#xA0;from&#xA0;emp;<br>+--------------------------------------------------+<br>|&#xA0;json_arrayagg(ename)&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------------------------+<br>|&#xA0;["emp_1001",&#xA0;"emp_1002",&#xA0;"emp_1003",&#xA0;"emp_1004"]&#xA0;|<br>+--------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;deptno,json_arrayagg(ename)&#xA0;from&#xA0;emp&#xA0;group&#xA0;by&#xA0;deptno;<br>+--------+--------------------------+<br>|&#xA0;deptno&#xA0;|&#xA0;json_arrayagg(ename)&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------+--------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;10&#xA0;|&#xA0;["emp_1001",&#xA0;"emp_1002"]&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;20&#xA0;|&#xA0;["emp_1003",&#xA0;"emp_1004"]&#xA0;|<br>+--------+--------------------------+<br>2&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_PRETTY(json_val)

将 JSON 格式化输出。

mysql>&#xA0;select&#xA0;json_pretty("[1,3,5]");<br>+------------------------+<br>|&#xA0;json_pretty("[1,3,5]")&#xA0;|<br>+------------------------+<br>|&#xA0;[<br>&#xA0;&#xA0;1,<br>&#xA0;&#xA0;3,<br>&#xA0;&#xA0;5<br>]&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_pretty('{"a":"10","b":"15","x":"25"}');<br>+---------------------------------------------+<br>|&#xA0;json_pretty('{"a":"10","b":"15","x":"25"}')&#xA0;|<br>+---------------------------------------------+<br>|&#xA0;{<br>&#xA0;&#xA0;"a":&#xA0;"10",<br>&#xA0;&#xA0;"b":&#xA0;"15",<br>&#xA0;&#xA0;"x":&#xA0;"25"<br>}&#xA0;&#xA0;&#xA0;|<br>+---------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_STORAGE_FREE(json_val)

MySQL 8.0 新增的,与 Partial Updates 有关,用于计算 JSON 文档在进行部分更新后的剩余空间。

JSON_STORAGE_SIZE(json_val)

MySQL 5.7.22 引入的,用于计算 JSON 文档的空间使用情况。

JSON_DEPTH(json_doc)

返回 JSON 文档的最大深度。对于空数组,空对象,标量值,其深度为 1。

mysql>&#xA0;select&#xA0;json_depth('{}'),json_depth('[10,&#xA0;20]'),json_depth('[10,&#xA0;{"a":&#xA0;20}]');<br>+------------------+------------------------+-------------------------------+<br>|&#xA0;json_depth('{}')&#xA0;|&#xA0;json_depth('[10,&#xA0;20]')&#xA0;|&#xA0;json_depth('[10,&#xA0;{"a":&#xA0;20}]')&#xA0;|<br>+------------------+------------------------+-------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;3&#xA0;|<br>+------------------+------------------------+-------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_LENGTH(json_doc[, path])

返回 JSON 文档的长度,其计算规则如下:

  1. 如果是标量值,其长度为 1。
  2. 如果是数组,其长度为数组元素的个数。
  3. 如果是对象,其长度为对象元素的个数。
  4. 不包括嵌套数据和嵌套对象的长度。
mysql>&#xA0;select&#xA0;json_length('"abc"');<br>+----------------------+<br>|&#xA0;json_length('"abc"')&#xA0;|<br>+----------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_length('[1,&#xA0;2,&#xA0;{"a":&#xA0;3}]');<br>+---------------------------------+<br>|&#xA0;json_length('[1,&#xA0;2,&#xA0;{"a":&#xA0;3}]')&#xA0;|<br>+---------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;3&#xA0;|<br>+---------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_length('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}');<br>+-----------------------------------------+<br>|&#xA0;json_length('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}')&#xA0;|<br>+-----------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;2&#xA0;|<br>+-----------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_length('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}',&#xA0;'$.a');<br>+------------------------------------------------+<br>|&#xA0;json_length('{"a":&#xA0;1,&#xA0;"b":&#xA0;{"c":&#xA0;30}}',&#xA0;'$.a')&#xA0;|<br>+------------------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_TYPE(json_val)

返回 JSON 值的类型。

mysql>&#xA0;select&#xA0;json_type('123');<br>+------------------+<br>|&#xA0;json_type('123')&#xA0;|<br>+------------------+<br>|&#xA0;INTEGER&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_type('"abc"');<br>+--------------------+<br>|&#xA0;json_type('"abc"')&#xA0;|<br>+--------------------+<br>|&#xA0;STRING&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_type(cast(now()&#xA0;as&#xA0;json));<br>+--------------------------------+<br>|&#xA0;json_type(cast(now()&#xA0;as&#xA0;json))&#xA0;|<br>+--------------------------------+<br>|&#xA0;DATETIME&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+--------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_type(json_extract('{"a":&#xA0;[10,&#xA0;true]}',&#xA0;'$.a'));<br>+-----------------------------------------------------+<br>|&#xA0;json_type(json_extract('{"a":&#xA0;[10,&#xA0;true]}',&#xA0;'$.a'))&#xA0;|<br>+-----------------------------------------------------+<br>|&#xA0;ARRAY&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;|<br>+-----------------------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_VALID(val)

判断给定值是否是有效的 JSON 文档。

mysql>&#xA0;select&#xA0;json_valid('hello'),&#xA0;json_valid('"hello"');<br>+---------------------+-----------------------+<br>|&#xA0;json_valid('hello')&#xA0;|&#xA0;json_valid('"hello"')&#xA0;|<br>+---------------------+-----------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+---------------------+-----------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_TABLE(expr, path COLUMNS (column_list) [AS] alias)

从 JSON 文档中提取数据并以表格的形式返回。

该函数的完整语法如下:

JSON_TABLE(<br>&#xA0;&#xA0;&#xA0;&#xA0;expr,<br>&#xA0;&#xA0;&#xA0;&#xA0;path&#xA0;COLUMNS&#xA0;(column_list)<br>)&#xA0;&#xA0;&#xA0;[AS]&#xA0;alias<br><br>column_list:<br>&#xA0;&#xA0;&#xA0;&#xA0;column[,&#xA0;column][,&#xA0;...]<br><br>column:<br>&#xA0;&#xA0;&#xA0;&#xA0;name&#xA0;FOR&#xA0;ORDINALITY<br>&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;name&#xA0;type&#xA0;PATH&#xA0;string_path&#xA0;[on_empty]&#xA0;[on_error]<br>&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;name&#xA0;type&#xA0;EXISTS&#xA0;PATH&#xA0;string_path<br>&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;NESTED&#xA0;[PATH]&#xA0;path&#xA0;COLUMNS&#xA0;(column_list)<br><br>on_empty:<br>&#xA0;&#xA0;&#xA0;&#xA0;{NULL&#xA0;|&#xA0;DEFAULT&#xA0;json_string&#xA0;|&#xA0;ERROR}&#xA0;ON&#xA0;EMPTY<br><br>on_error:<br>&#xA0;&#xA0;&#xA0;&#xA0;{NULL&#xA0;|&#xA0;DEFAULT&#xA0;json_string&#xA0;|&#xA0;ERROR}&#xA0;ON&#xA0;ERROR

其中,

  • expr:可以返回 JSON 文档的表达式。可以是一个标量( JSON 文档 ),列名或者一个函数调用( JSON_EXTRACT(t1.json_data,’$.post.comments’) )。
  • path:JSON 的路径表达式,
  • column:列的类型,支持以下四种类型:
  • name FOR ORDINALITY:序号。name 是列名。
  • name type PATH string_path [on_empty] [on_error]:提取指定路径( string_path )的元素。name 是列名,type 是 MySQL 中的数据类型。
  • name type EXISTS PATH string_path:指定路径( string_path )的元素是否存在。
  • NESTED [PATH] path COLUMNS (column_list):将嵌套对象或数组与来自父对象或数组的 JSON 值扁平化为一行输出。
select&#xA0;*<br>&#xA0;from<br>&#xA0;&#xA0;&#xA0;json_table(<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;'[{"x":2,&#xA0;"y":"8",&#xA0;"z":9,&#xA0;"b":[1,2,3]},&#xA0;{"x":"3",&#xA0;"y":"7"},&#xA0;{"x":"4",&#xA0;"y":6,&#xA0;"z":10}]',<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"$[*]"&#xA0;columns(<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;id&#xA0;for&#xA0;ordinality,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;xval&#xA0;varchar(100)&#xA0;path&#xA0;"$.x",<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;yval&#xA0;varchar(100)&#xA0;path&#xA0;"$.y",<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;z_exist&#xA0;int&#xA0;exists&#xA0;path&#xA0;"$.z",<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;nested&#xA0;path&#xA0;'$.b[*]'&#xA0;columns&#xA0;(b&#xA0;INT&#xA0;PATH&#xA0;'$')<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;)<br>&#xA0;&#xA0;&#xA0;)&#xA0;as&#xA0;t;<br>+------+------+------+---------+------+<br>|&#xA0;id&#xA0;&#xA0;&#xA0;|&#xA0;xval&#xA0;|&#xA0;yval&#xA0;|&#xA0;z_exist&#xA0;|&#xA0;b&#xA0;&#xA0;&#xA0;&#xA0;|<br>+------+------+------+---------+------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;2&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;8&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;2&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;8&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;2&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;2&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;8&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;3&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;2&#xA0;|&#xA0;3&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;7&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|&#xA0;NULL&#xA0;|<br>|&#xA0;&#xA0;&#xA0;&#xA0;3&#xA0;|&#xA0;4&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;6&#xA0;&#xA0;&#xA0;&#xA0;|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|&#xA0;NULL&#xA0;|<br>+------+------+------+---------+------+<br>5&#xA0;rows&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

JSON_SCHEMA_VALID(schema,document)

判断 document ( JSON 文档 )是否满足 schema ( JSON 对象)定义的规范要求。完整的规范要求可参考 Draft 4 of the JSON Schema specification 。如果不满足,可通过 JSON_SCHEMA_VALIDATION_REPORT() 获取具体的原因。

以下面这个 schema 为例。

set&#xA0;@schema&#xA0;=&#xA0;'{<br>&#xA0;&#xA0;&#xA0;"type":&#xA0;"object",<br>&#xA0;&#xA0;&#xA0;"properties":&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"latitude":&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"type":&#xA0;"number",<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"minimum":&#xA0;-90,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"maximum":&#xA0;90<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;},<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"longitude":&#xA0;{<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"type":&#xA0;"number",<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"minimum":&#xA0;-180,<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;"maximum":&#xA0;180<br>&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;}<br>&#xA0;&#xA0;&#xA0;},<br>&#xA0;&#xA0;&#xA0;"required":&#xA0;["latitude",&#xA0;"longitude"]<br>}';

它的要求如下:

  1. document 必须是 JSON 对象。
  2. JSON 对象必需的两个属性是 latitude 和 longitude。
  3. latitude 和 longitude 必须是数值类型,且两者的大小分别在 -90 ~ 90,-180 ~ 180 之间。

下面通过具体的 document 来测试一下。

mysql>&#xA0;set&#xA0;@document&#xA0;=&#xA0;'{"latitude":&#xA0;63.444697,"longitude":&#xA0;10.445118}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_schema_valid(@schema,&#xA0;@document);<br>+---------------------------------------+<br>|&#xA0;json_schema_valid(@schema,&#xA0;@document)&#xA0;|<br>+---------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;1&#xA0;|<br>+---------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;set&#xA0;@document&#xA0;=&#xA0;'{"latitude":&#xA0;63.444697}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_schema_valid(@schema,&#xA0;@document);<br>+---------------------------------------+<br>|&#xA0;json_schema_valid(@schema,&#xA0;@document)&#xA0;|<br>+---------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+---------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_pretty(json_schema_validation_report(@schema,&#xA0;@document))\G<br>***************************&#xA0;1.&#xA0;row&#xA0;***************************<br>json_pretty(json_schema_validation_report(@schema,&#xA0;@document)):&#xA0;{<br>&#xA0;&#xA0;"valid":&#xA0;false,<br>&#xA0;&#xA0;"reason":&#xA0;"The&#xA0;JSON&#xA0;document&#xA0;location&#xA0;'#'&#xA0;failed&#xA0;requirement&#xA0;'required'&#xA0;at&#xA0;JSON&#xA0;Schema&#xA0;location&#xA0;'#'",<br>&#xA0;&#xA0;"schema-location":&#xA0;"#",<br>&#xA0;&#xA0;"document-location":&#xA0;"#",<br>&#xA0;&#xA0;"schema-failed-keyword":&#xA0;"required"<br>}<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;set&#xA0;@document&#xA0;=&#xA0;'{"latitude":&#xA0;91,"longitude":&#xA0;0}';<br>Query&#xA0;OK,&#xA0;0&#xA0;rows&#xA0;affected&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_schema_valid(@schema,&#xA0;@document);<br>+---------------------------------------+<br>|&#xA0;json_schema_valid(@schema,&#xA0;@document)&#xA0;|<br>+---------------------------------------+<br>|&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;&#xA0;0&#xA0;|<br>+---------------------------------------+<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)<br><br>mysql>&#xA0;select&#xA0;json_pretty(json_schema_validation_report(@schema,&#xA0;@document))\G<br>***************************&#xA0;1.&#xA0;row&#xA0;***************************<br>json_pretty(json_schema_validation_report(@schema,&#xA0;@document)):&#xA0;{<br>&#xA0;&#xA0;"valid":&#xA0;false,<br>&#xA0;&#xA0;"reason":&#xA0;"The&#xA0;JSON&#xA0;document&#xA0;location&#xA0;'#/latitude'&#xA0;failed&#xA0;requirement&#xA0;'maximum'&#xA0;at&#xA0;JSON&#xA0;Schema&#xA0;location&#xA0;'#/properties/latitude'",<br>&#xA0;&#xA0;"schema-location":&#xA0;"#/properties/latitude",<br>&#xA0;&#xA0;"document-location":&#xA0;"#/latitude",<br>&#xA0;&#xA0;"schema-failed-keyword":&#xA0;"maximum"<br>}<br>1&#xA0;row&#xA0;in&#xA0;set&#xA0;(0.00&#xA0;sec)

八、总结

如果要使用 JSON 类型,推荐使用 MySQL 8.0。相比于 MySQL 5.7,Partial update 带来的性能提升还是十分明显的。

Partial update 在存储引擎层是默认开启的,binlog 中是否开启取决于 binlog_row_value_options 。该参数默认为空,不会开启 Partial update,建议设置为 PARTIAL_JSON。

注意使用 Partial update 的前提条件。

当我们使用 JSON_CONTAINS、MEMBER OF、JSON_OVERLAPS 进行数组相关的操作时,可使用 MySQL 8.0.17 引入的多值索引来加快查询。

九、参考资料

  1. JSON
  2. The JSON Data Type
  3. JSON Functions
  4. Upgrading JSON data stored in TEXT columns
  5. Indexing JSON documents via Virtual Columns
  6. Partial update of JSON values
  7. MySQL 8.0: InnoDB Introduces LOB Index For Faster Updates

Original: https://www.cnblogs.com/ivictor/p/16221712.html
Author: iVictor
Title: 一文说透 MySQL JSON 数据类型(收藏)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/505412/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球