一文说透 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)

大家都在看

  • Tomcat8下的Redis会话共享

    前言: 最近在做网站的升级,从 Tomcat7升级到 Tomcat8版本,因为没接触过,就以为升级下Tomcat的版本就万事大吉,可是天不如人愿,很顺利的将应用升级到了Tomcat…

    数据库 2023年6月14日
    0101
  • 深入浅出分析 ArrayDeque

    作者:炸鸡可乐原文出处:www.pzblog.cn 一、摘要 在 jdk1.5 中,新增了 Queue 接口,代表一种队列集合的实现,咱们继续来聊聊 java 集合体系中的 Que…

    数据库 2023年6月14日
    086
  • docker部署mysql集群

    docker部署mysql集群 1.0 安装环境 1.1 安装Centos7 Docker官方建议在Ubuntu中安装,因为Docker是基于Ubuntu发布的,而且一般Docke…

    数据库 2023年6月9日
    088
  • lvs负载均衡

    Lvs 一.Lvs简介 二. 体系结构 三. Lvs管理工具 1. ipvs 2. ipvsadm 四.lvs工作模式及原理 1.NAT模式 2. DR模式 3.TUN模式(隧道模…

    数据库 2023年6月14日
    090
  • Executor 创建线程

    Executors创建有四种创建方式: newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIF…

    数据库 2023年6月9日
    088
  • -B+树索引和HASH索引有哪些不一样【MySQL系列】

    我们都理解B+树和Hash索引的区别有助于我们预测索引在不同的存储引擎中是怎么执行查询的。 B+ TREE 索引特性B数是一种在数据库索引中流行的树数据结构。该结构始终保持排序,从…

    数据库 2023年5月24日
    0100
  • 条件控制

    1. 顺序结构 java代码顺序执行 2. 选择结构 if语句 格式 if(结果为booblean类型的表达式){ 语句体; } if(结果为booblean类型的表达式){ 语句…

    数据库 2023年6月14日
    049
  • Simple SNMP with SimpleSnmp

    Apparently not everybody is as interested in the background workings of the SNMP protocol …

    数据库 2023年6月11日
    089
  • redis 从安装到实现远程连接–centos7下

    Java 端配置 上面的配置完成后,我们可以创建一个普通的 JavaSE 工程来测试下了,Java 工程创建成功后,添加 Jedis 依赖,如下 然后我们可以通过如下一个简单的程序…

    数据库 2023年6月16日
    077
  • 银河麒麟V10安装MySQL8028

    记一次成功安装MySQL8028到银河麒麟V10,并实现远程访问的方法 工具/原料 数据库下载地址(实验版如图): [En] Download address of the dat…

    数据库 2023年5月24日
    085
  • 面试官:请用SQL模拟一个死锁

    文章首发于公众号:BiggerBoy 有读者说面试被问到怎么用SQL模拟数据库死锁?这位读者表示对Java中的死锁还是略知一二的,但是突然用SQL写死锁的案例之前还真没遇到过,这个…

    数据库 2023年5月24日
    0171
  • Spring(四)-声明式事务

    Spring-04 声明式事务 1、事务的定义 事务就是由 一组逻辑上紧密关联的 多个工作单元(数据库操作)而合并成一个整体,这些操作 要么都执行,要么都不执行。 2、事务的特性:…

    数据库 2023年6月16日
    0111
  • Windows10 下使用 telnet 命令

    正常情况下 windows 是使用不了 telnet 命令的: 打开控制面板-》程序和功能-》启用或关闭 Windows 功能 勾选 “Telnet客户端”…

    数据库 2023年6月14日
    074
  • Centos7开放及查看端口

    Centos7开放及查看端口 1、开放端口 firewall-cmd –zone=public –add-port=5672/tcp –permanent # &#x…

    数据库 2023年6月6日
    098
  • com.mysql.cj.jdbc.Driver和com.mysql.jdbc.Driver的区别

    今天,我在写作考试中发现了一个问题,如下所示: [En] Today, I found a problem during the writing test, as follows:…

    数据库 2023年5月24日
    060
  • Linux_文件传输工具_FileZilla

    FileZilla功能介绍: Filezilla是如此容易的下载和启动,你可能不会意识到它是多么强大。只需输入几个基本的服务器设置,您就可以点击一下启动并运行。要上传和下载文件,只…

    数据库 2023年6月11日
    096
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球