JSON in MySQL
创建JSON值
一个JSON数组包含了一组由方括号包裹的,由逗号分隔的值:
["json", null, true, 123]
一个JSON对象包含了一组由花括号包裹的一组键值对,键值对之间用逗号分隔:
{"key": "value", "key2": 2}
JSON数组和对象可以包含字符串和数字这样纯量的值,JSON的null值字面量,或者JSON布尔值字面量(true/false)。在JSON对象中,键必须时字符串。表示时间的纯量值也可以在JSON中使用:
["2019-10-01 13:21:02.000022", "2011-09-28"]
在JSON数组,JSON对象中的value也可以嵌套使用JSON数组/对象,例如:
[100,{"name":"Jane", "age": 19},[21, 28]]
{"key1":[21,20], "key2":"value"}
JSON值可以通过MySQL提供的一些方法来创建,也可以使用CAST(value AS JSON)
将其他类型的值转换为JSON类型。
在MySQL中,JSON值被写作为字符串。MySQL会在需要JSON值的环境下将任何字符串转换为JSON值,如果字符串不是一个有效的JSON值,MySQL会报错。这些环境包括:向某个数据类型为JSON
的字段插入数据时,或是向某个参数类型为JSON
的函数传入参数时等。
除了使用字面量编写JSON值外,还有一些函数可以将各部分的值组合成JSON值。
例如:JSON_ARRAY()
接收一组值,返回一个包含了这些值的JSON数组;
mysql> SELECT JSON_ARRAY('a', 1, NOW());
+----------------------------------------+
| JSON_ARRAY('a', 1, NOW()) |
+----------------------------------------+
| ["a", 1, "2019-04-23 10:34:07.000000"] |
+----------------------------------------+
1 row in set (0.01 sec)
JSON_OBJECT()
接收一系列的键值对,返回一个包含了这些键值对的JSON对象。如果输入的参数列表中,键值对的键名发生了重复,先输入的键值对(位于参数列表前端)将被覆盖,输出的结果中只包含重复键值对中最后一个输入的值(位于参数列表尾端);
mysql> SELECT JSON_OBJECT('key1','value1','key2',2);
+---------------------------------------+
| JSON_OBJECT('key1','value1','key2',2) |
+---------------------------------------+
| {"key1": "value1", "key2": 2} |
+---------------------------------------+
1 row in set (0.00 sec)
mysql> SELECT JSON_OBJECT('key1',1,'key2','abc','key1','def');
+-------------------------------------------------+
| JSON_OBJECT('key1',1,'key2','abc','key1','def') |
+-------------------------------------------------+
| {"key1": "def", "key2": "abc"} |
+-------------------------------------------------+
1 row in set (0.00 sec)
JSON_MERGE_PRESERVE()
接收两个或两个以上的JSON文件,返回一个合并后的结果;
mysql> SELECT JSON_MERGE_PRESERVE('{"key1":1,"key2":2}','[2,"abc"]');
+--------------------------------------------------------+
| JSON_MERGE_PRESERVE('{"key1":1,"key2":2}','[2,"abc"]') |
+--------------------------------------------------------+
| [{"key1": 1, "key2": 2}, 2, "abc"] |
+--------------------------------------------------------+
1 row in set (0.00 sec)
JSON值是大小写敏感的,因此在使用null,true,false
这些字面量时,一定要使用小写字母。相比之下,SQL中的字面量NULL,TRUE,FALSE
则是大小写不敏感的,可以使用任何形式来表示。
MySQL中支持两种合并方法,JSON_MERGE_PRESERVE()
和JSON_MERGE_PATCH()
。二者的区别在于如何处理重复的键:JSON_MERGE_PRESERVE()
保留重复的键,而JSON_MERGE_PATCH()
只保留最后一个值,其他值都会被丢弃。
-
合并数组
JSON_MERGE_PRESERVE()
会将所有数组拼接起来形成一个新数组并返回。而JSON_MERGE_PATCH()
只会保留最后一个数组,并将其作为结果返回。mysql> SELECT JSON_MERGE_PRESERVE('[1,2]','["A","B"]','[true,false]'); +---------------------------------------------------------+ | JSON_MERGE_PRESERVE('[1,2]','["A","B"]','[true,false]') | +---------------------------------------------------------+ | [1, 2, "A", "B", true, false] | +---------------------------------------------------------+ 1 row in set (0.00 sec) mysql> SELECT JSON_MERGE_PATCH('[1,2]','["A","B"]','[true,false]'); +------------------------------------------------------+ | JSON_MERGE_PATCH('[1,2]','["A","B"]','[true,false]') | +------------------------------------------------------+ | [true, false] | +------------------------------------------------------+ 1 row in set (0.00 sec)
-
合并对象
当要合并的多个对象中含有相同的键时,
JSON_MERGE_PRESERVE()
会将重复的键对应的所有值去重后存入一个数组中作为该键的值,再将该键值对存入对象中返回。JSON_MERGE_PATCH()
则会从左到右依次丢弃重复键的值,只保留最后一个出现的值。mysql> SELECT JSON_MERGE_PERSERVE('{"a":1,"b":2}','{"c":3,"a":4}','{"c":5,"d":3}'); ERROR 1046 (3D000): No database selected mysql> SELECT JSON_MERGE_PRESERVE('{"a":1,"b":2}','{"c":3,"a":4}','{"c":5,"d":3}'); +----------------------------------------------------------------------+ | JSON_MERGE_PRESERVE('{"a":1,"b":2}','{"c":3,"a":4}','{"c":5,"d":3}') | +----------------------------------------------------------------------+ | {"a": [1, 4], "b": 2, "c": [3, 5], "d": 3} | +----------------------------------------------------------------------+ 1 row in set (0.00 sec) mysql> SELECT JSON_MERGE_PATCH('{"a":1,"b":2}','{"c":3,"a":4}','{"c":5,"d":3}'); +-------------------------------------------------------------------+ | JSON_MERGE_PATCH('{"a":1,"b":2}','{"c":3,"a":4}','{"c":5,"d":3}') | +-------------------------------------------------------------------+ | {"a": 4, "b": 2, "c": 5, "d": 3} | +-------------------------------------------------------------------+ 1 row in set (0.00 sec)
-
合并值
当传入的参数既不是数组,也不是对象,而是单独的值时,这个值会被自动用方括号包裹转换成数组,然后按照合并数组的规则进行合并。
mysql> SELECT JSON_MERGE_PRESERVE('1','2'); +------------------------------+ | JSON_MERGE_PRESERVE('1','2') | +------------------------------+ | [1, 2] | +------------------------------+ 1 row in set (0.00 sec) mysql> SELECT JSON_MERGE_PATCH('1','2'); +---------------------------+ | JSON_MERGE_PATCH('1','2') | +---------------------------+ | 2 | +---------------------------+ 1 row in set (0.00 sec)
-
合并数组和对象
当合并的对象既有数组也有对象时,对象会被自动包装转换成数组进行合并操作,然后按照合并数组的规则进行合并。
mysql> SELECT JSON_MERGE_PRESERVE('[10,11]','{"key1": 1, "key2": 2}'); +---------------------------------------------------------+ | JSON_MERGE_PRESERVE('[10,11]','{"key1": 1, "key2": 2}') | +---------------------------------------------------------+ | [10, 11, {"key1": 1, "key2": 2}] | +---------------------------------------------------------+ 1 row in set (0.00 sec) mysql> SELECT JSON_MERGE_PATCH('[10,11]','{"key1": 1, "key2": 2}'); +------------------------------------------------------+ | JSON_MERGE_PATCH('[10,11]','{"key1": 1, "key2": 2}') | +------------------------------------------------------+ | {"key1": 1, "key2": 2} | +------------------------------------------------------+ 1 row in set (0.00 sec)
搜索和修改JSON值
一个路径表达式(path expression)可以在一个JSON文档中选择一个值。当我们需要从一个JSON文档中提取或者修改一部分值时,路径表达式十分有用,我们可以使用路径表达式明确得指出需要修改的部分。
路径表达式的语法使用一个先导的$
来代表需要进行操作的JSON文档,具体的语法如下:
pathExpression:
scope[(pathLeg)*]
pathLeg:
member | arrayLocation | doubleAsterisk
member:
period ( keyName | asterisk )
arrayLocation:
leftBracket ( nonNegativeInteger | asterisk ) rightBracket
keyName:
ESIdentifier | doubleQuotedString
doubleAsterisk:
'**'
period:
'.'
asterisk:
'*'
leftBracket:
'['
rightBracket:
']'
大体上讲,.
可以选择某个键对应的值,[]
可以选择数组中的某个值或者某个范围的值,*
通配符可以选择某个指定范围的值。与路径表达式配合使用一些方法,可以实现搜索和修改JSON值,这些方法常见的有:
JSON_EXTRACT()
—提取某个值
mysql> SELECT JSON_EXTRACT('{"a":1,"b":2,"c":[3,4,5]}','$.c[*]');
+----------------------------------------------------+
| JSON_EXTRACT('{"a":1,"b":2,"c":[3,4,5]}','$.c[*]') |
+----------------------------------------------------+
| [3, 4, 5] |
+----------------------------------------------------+
1 row in set (0.00 sec)
JSON_SET()
—若路径对应的值存在,替换这个值,如果不存在则添加新值。
mysql> SELECT JSON_SET('{"key1":1, "key2":2}', '$.key1', 2);
+-----------------------------------------------+
| JSON_SET('{"key1":1, "key2":2}', '$.key1', 2) |
+-----------------------------------------------+
| {"key1": 2, "key2": 2} |
+-----------------------------------------------+
1 row in set (0.00 sec)
JSON_INSERT()
—添加新值,但是不替换已经存在的值(忽略旧值)
mysql> SELECT JSON_INSERT('[1,2,3]', '$[0]', 0, '$[3]', 4);
+----------------------------------------------+
| JSON_INSERT('[1,2,3]', '$[0]', 0, '$[3]', 4) |
+----------------------------------------------+
| [1, 2, 3, 4] |
+----------------------------------------------+
1 row in set (0.01 sec)
JSON_REPLACE()
—替换已经存在的值,忽略新值
mysql> SELECT JSON_REPLACE('[1,2,3]', '$[0]', 0, '$[3]', 4);
+-----------------------------------------------+
| JSON_REPLACE('[1,2,3]', '$[0]', 0, '$[3]', 4) |
+-----------------------------------------------+
| [0, 2, 3] |
+-----------------------------------------------+
1 row in set (0.00 sec)
JSON_REMOVE()
—删除某个值
mysql> SELECT JSON_REMOVE('[[1,2],{"key1":1, "key2":"value2"}]', '$[1].key1');
+-----------------------------------------------------------------+
| JSON_REMOVE('[[1,2],{"key1":1, "key2":"value2"}]', '$[1].key1') |
+-----------------------------------------------------------------+
| [[1, 2], {"key2": "value2"}] |
+-----------------------------------------------------------------+
1 row in set (0.00 sec)
比较和排序JSON值
JSON值可以通过使用=
,<
,<=
,>
,>=
,<>
,!=
和<=>
操作符进行比较。
JSON值不支持使用一下操作符/函数进行比较:
BETWEEN
IN()
GREATEST()
LEAST()