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

大家都在看

  • 实现一个简单的Database2(译文)

    前文回顾:实现一个简单的Database1(译文) 译注:cstsck在github维护了一个简单的、类似sqlite的数据库实现,通过这个简单的项目,可以很好的理解数据库是如何运…

    数据库 2023年6月11日
    0125
  • MySQL中 VARCHAR 可设置的最大长度是多少?

    在使用MySQL的过程中,在存储字符串时,大家或许都有过这样或那样的困惑,譬如: 对于固定长度的字符串,为什么推荐使用 CHAR 来存储? VARCHAR 可设置的最大长度是多少?…

    数据库 2023年6月11日
    0109
  • docker安装下载

    一、docker安装 &#x67E5;&#x770B; sudo systemctl status docker &#x5B89;&#x88C5; …

    数据库 2023年6月9日
    099
  • 什么?MySQL 8.0 会同时修改两个ib_logfilesN 文件?

    GreatSQL社区原创内容未经授权不得随意使用,转载请联系小编并注明来源。 GreatSQL是MySQL的国产分支版本,使用上与MySQL一致。 作者介绍:孙黎,GreatDB …

    数据库 2023年6月11日
    0119
  • 有趣的特性:CHECK约束

    功能说明 在MySQL 8.0.16以前, CREATE TABLE允许从语法层面输入下列 CHECK约束,但实际没有效果: CHECK (expr) 在 MySQL 8.0.16…

    数据库 2023年5月24日
    059
  • MySQL主从备库过滤参数分析和测试

    测试环境: GTID的主从复制,主库(9900)——》备库(9909),存在测试库表: 9900_db1库:t1、t2、t3、t4、t5表 9900_db2库:t6、t7、t8、t…

    数据库 2023年5月24日
    076
  • 设计模式之(3)——抽象工厂方法模式

    定义:抽象工厂模式简单地讲,就是提供一个超级工厂,围绕这个超级工厂创建其他工厂;抽象工厂模式提供一个创建一些列相关或者相互依赖对象的接口; 在此之前我们先来讲一下产品等级和产品族的…

    数据库 2023年6月14日
    088
  • index_merge引发的死锁排查

    前几天排查了一个死锁问题,最开始百思不得其解,因为发生死锁的两个事务是单语句事务,语句类型相同(where属性列相同,仅值不同),而且语句都走了相同的索引,但最终确实发生了死锁。通…

    数据库 2023年6月9日
    0126
  • 分享攒了多年的mssql脚本

    分享攒了多年的mssql脚本 脚本类别包括:备份还原表分区常用函数错误日志定时自动抓取耗时SQL并归档发邮件脚本模块镜像批量脚本数据库收缩数据库损坏数据库账号统计数据库大小性能作业…

    数据库 2023年6月9日
    0107
  • Mysql8设置允许root用户远程访问

    按照mysql8.0以前的方法修改报错 mysql> grant all privileges on *.* to ‘root’@’%’ identified by ‘PAS…

    数据库 2023年6月6日
    0134
  • Java 线程是如何启动的?

    Java启动线程的代码: 根据以上代码分析,并从源码了解启动线程发生了以下事件来完成启动线程: 1、Java 创建线程和启动 2、调用本地方法 start0(); 3、JVM 中 …

    数据库 2023年6月16日
    0103
  • redis简述

    redis是什么? Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、…

    数据库 2023年6月14日
    084
  • 查看PostgreSQL监听端口

    如何查看PostgreSQL的监听端口呢?下面总结一下查看PostgreSQL监听端口的方法。 方法1:netstat命令查看 或者sudo netstat -plunt |gre…

    数据库 2023年6月11日
    090
  • mysql常用语句 4 + mysql的约束(非空,唯一,主键,外键)

    1.更新语句update dept1 set loc = ‘wz’,dname = ‘xueshenghui’ where dept…

    数据库 2023年5月24日
    0101
  • Html转换PDF(Java实用版)

    前言: 在工作当中,遇到了需要把HTML页面转化为PDF文档,有很多中实现,如下进行一个对比,大家个借鉴去进行使用 各实现对比表 于Windows平台进行测试: 此博客仅基于ITe…

    数据库 2023年6月16日
    0123
  • MySQL实现阶段累加的sql写法 ,eq:统计余额

    最近项目碰到一个新的需求,统计每日充值/消费之后的余额。对于这种需求,其实也很简单,只需要在每次充值/消费后,计算下余额,然后保存下来就可以了。但是对于这种需求,一条sql就能搞定…

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