mysql JSON更新、插入、查询语法的最佳实践
MySQL 从 5.7.8 版本开始支持 JSON 类型。 我看到很多关于如何选择的文章,但是有一些关于实际更新和插入、查询的内容很短,所以我就在这里总结一下。
开始前
创建一张带有json
类型字段的表.
create table example (id int, a json);
插入一条a列为null
的测试数据.
mysql> insert into example values (1,null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from example;
+------+------+
| id | a |
+------+------+
| 1 | NULL |
+------+------+
1 row in set (0.00 sec)
插入
JSON_OBJECT方法
使用json_object
生成json
对象.
JSON_OBJECT([key, val[, key, val] ...])
mysql> insert into example values (2, JSON_OBJECT('key1','val1', 'key2', 'val2'));
Query OK, 1 row affected (0.00 sec)
mysql> select * from example where id=2;
+------+----------------------------------+
| id | a |
+------+----------------------------------+
| 2 | {"key1": "val1", "key2": "val2"} |
+------+----------------------------------+
1 row in set (0.01 sec)
如果你的键值为奇数个,你会得到一个错误。
mysql> insert into example values (3, JSON_OBJECT('key1','val1', 'key2', 'val2', 'aaa'));
ERROR 1582 (42000): Incorrect parameter count in the call to native function 'JSON_OBJECT'
JSON_ARRAY方法
使用json_array
来放置一个数组。 数值、字符串和 mysql 函数可一起使用。
JSON_ARRAY([val[, val] ...])
mysql> insert into example values (4, JSON_ARRAY('aaa','bbb', 1, now()));
Query OK, 1 row affected (0.00 sec)
mysql> select * from example where id=4;
+------+-------------------------------------------------+
| id | a |
+------+-------------------------------------------------+
| 4 | ["aaa", "bbb", 1, "2020-01-22 14:40:42.000000"] |
+------+-------------------------------------------------+
1 row in set (0.00 sec)
可以把json_object
放入json_array
一起使用.
mysql> insert into example values
(5, JSON_ARRAY('aaa','bbb', 1, now(), JSON_OBJECT('key1','val1', 'key2', 'val2')));
Query OK, 1 row affected (0.00 sec)
mysql> select * from example where id=5;
+------+-----------------------------------------------------------------------------------+
| id | a |
+------+-----------------------------------------------------------------------------------+
| 5 | ["aaa", "bbb", 1, "2020-01-22 14:42:25.000000", {"key1": "val1", "key2": "val2"}] |
+------+-----------------------------------------------------------------------------------+
1 row in set (0.00 sec)
更新
JSON_MERGE方法
如果你想将键值添加到JSON
对象中使用json_merge
.
JSON_MERGE(json_doc, json_doc[, json_doc] ...)
-- 两者都可以。
update example set a=json_merge(a, json_object('key3', 'val3')) where id=2;
update example set a=json_merge(a, '{"key4": "val4"}') where id=2;
mysql> select * from example where id=2;
+------+------------------------------------------------------------------+
| id | a |
+------+------------------------------------------------------------------+
| 2 | {"key1": "val1", "key2": "val2", "key3": "val3", "key4": "val4"} |
+------+------------------------------------------------------------------+
JSON_ARRAY_APPEND
如果你想将值添加到JSON
数组中使用json_array_append
.
JSON_ARRAY_APPEND(json_doc, path, val[, path, val] ...)
对于路径,指定要从开始放置的层次结构等。[点击此处](https://dev.mysql.com/doc/refman/8.0/en/json.html#json−path−syntax)了解详情。这次,它会被放在第一层,所以只有开始放置的层次结构等。 [点击此处](https://dev.mysql.com/doc/refman/8.0/en/json.html\#json-path-syntax)了解详情。 这次,它会被放在第一层,所以只有开始放置的层次结构等。[点击此处](https://dev.mysql.com/doc/refman/8.0/en/json.html#json−path−syntax)了解详情。这次,它会被放在第一层,所以只有。
mysql> update example set a=json_array_append(a, '$', 'hyoo') where id=4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from example where id=4;
+------+---------------------------------------------------------+
| id | a |
+------+---------------------------------------------------------+
| 4 | ["aaa", "bbb", 1, "2020-01-22 15:00:39.000000", "hyoo"] |
+------+---------------------------------------------------------+
1 row in set (0.00 sec)
您也可以通过更改路径来执行类似的操作.
mysql> update example set a=json_array_append(a, '$[3]', 'ttt') where id=4;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from example where id=4;
+------+------------------------------------------------------------------+
| id | a |
+------+------------------------------------------------------------------+
| 4 | ["aaa", "bbb", 1, ["2020-01-22 15:00:39.000000", "ttt"], "hyoo"] |
+------+------------------------------------------------------------------+
1 row in set (0.00 sec)
原数据为NULL
mysql> select * from example where id=1;
+------+------+
| id | a |
+------+------+
| 1 | NULL |
+------+------+
1 row in set (0.00 sec)
mysql> update example set a= json_array_append(a, '$', 'hyo') where id=1;
Query OK, 0 rows affected (0.00 sec)
Rows matched: 1 Changed: 0 Warnings: 0
mysql> select * from example where id=1;
+------+------+
| id | a |
+------+------+
| 1 | NULL |
+------+------+
1 row in set (0.00 sec)
可以看到直接更新是不生效的. 我们需要使用ifnull
来解决这个问题.
json_array示例
mysql> select * from example where id=1;
+------+------+
| id | a |
+------+------+
| 1 | NULL |
+------+------+
1 row in set (0.00 sec)
mysql> update example set
-> a=ifnull(json_array_append(a, '$', 'hyo'), json_array('hyo'))
-> where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from example where id=1;
+------+---------+
| id | a |
+------+---------+
| 1 | ["hyo"] |
+------+---------+
1 row in set (0.00 sec)
json_object示例
mysql> select * from example where id=1;
+------+------+
| id | a |
+------+------+
| 1 | NULL |
+------+------+
1 row in set (0.01 sec)
mysql> update example set
a=ifnull(
json_array_append(a, '$', json_object('comment','munya_munya','created_at', now())),
json_array(json_object('comment','hogefuga','created_at', now()))
) where id=1;
Query OK, 1 row affected (0.01 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from example where id=1; +------+-----------------------------------------------------------------------+
| id | a |
+------+-----------------------------------------------------------------------+
| 1 | [{"comment": "hogefuga", "created_at": "2020-01-22 15:08:33.000000"}] |
+------+-----------------------------------------------------------------------+
1 row in set (0.00 sec)
mysql> update example set
a=ifnull(
json_array_append(a, '$', json_object('comment','munya_munya','created_at', now())),
json_array(json_object('comment','hogefuga','created_at', now()))
) where id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from example where id=1; +------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| id | a |
+------+-----------------------------------------------------------------------------------------------------------------------------------------------+
| 1 | [{"comment": "hogefuga", "created_at": "2020-01-22 15:08:33.000000"}, {"comment": "munya_munya", "created_at": "2020-01-22 15:08:48.000000"}] |
+------+-----------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
查询
JSON_EXTRACT
如果需要从json
串中提取值就需要使用JSON_EXTRACT
函数来操作。
添加一些测试数据
mysql> create table sample(id int null,text json null);
> insert into `sample` (`id`, `text`) value(1, '{"id": 1, "label": "sample", "value": "test"}');
> insert into `sample` (`id`, `text`) value(2, '{"id": 2, "label": "sample2", "value": "test2"}');
> insert into `sample` (`id`, `text`) value(3, '{"id": 3, "label": "sample3", "value": "test3"}');
找出
text
字段中id
大于等于2的数据.
mysql> select * from sample where JSON_EXTRACT(text, '$.id') >= 2;
+------+-------------------------------------------------+
| id | text |
+------+-------------------------------------------------+
| 2 | {"id": 2, "label": "sample2", "value": "test2"} |
| 3 | {"id": 3, "label": "sample3", "value": "test3"} |
+------+-------------------------------------------------+
2 rows in set (0.01 sec)
只显示
json
中指定的字段值
mysql> select json_extract(text, '$.value') from sample;
+-------------------------------+
| json_extract(text, '$.value') |
+-------------------------------+
| "test2" |
| "test" |
| "test3" |
+-------------------------------+
3 rows in set (0.00 sec)
在mysql版本>=5.7.9中有更快捷的方法来代替
json_extract
函数. 使用json->
就可以提取访问值.
mysql> select text->'$.value' from sample;
+-----------------+
| text->'$.value' |
+-----------------+
| "test2" |
| "test" |
| "test3" |
+-----------------+
3 rows in set (0.00 sec)
对提取的值做聚合(
SUM
,AVG
,MIN
,MAX
)操作
mysql> select SUM(text->'$.id') from sample;
+-------------------+
| SUM(text->'$.id') |
+-------------------+
| 6 |
+-------------------+
1 row in set (0.00 sec)
JSON_CONTAINS
使用json_contains
来代替等于 查询,mysql针对此函数有更好的优化。
mysql> select * from sample where JSON_CONTAINS(`text`, '"test2"', '$.value');
+------+-------------------------------------------------+
| id | text |
+------+-------------------------------------------------+
| 2 | {"id": 2, "label": "sample2", "value": "test2"} |
+------+-------------------------------------------------+
1 row in set (0.01 sec)
请注意查询语句中的
'"text2"'
, 如果你查询的字段值类型是字符串形式需要以’""'来包含字符串. 在测试一次整数类型。
mysql> select * from sample where JSON_CONTAINS(`text`, '1', '$.id');
+------+-----------------------------------------------+
| id | text |
+------+-----------------------------------------------+
| 1 | {"id": 1, "label": "sample", "value": "test"} |
+------+-----------------------------------------------+
1 row in set (0.00 sec)
JSON_CONTAINS_PATH
json_contains
只能查询json
中路径的值包含某个值, 如果需要查询json
包含某个路径就需要使用json_contains_path
.
JSON_CONTAINS_PATH(_json_doc_, _one_or_all_, _path_[, _path_] ...)
第一个参数是json
字段,第二参数是one
或者all
固定的两个值. 后面的参数就是需要查的路径.
- ‘one’:如果文档中至少存在一个路径,则为 1,否则为 0。
- ‘all’:如果文档中存在所有路径,则为 1,否则为 0。
来个示例说明下one
和all
的作用.
mysql> select * from sample where json_contains_path(`text`, 'one', '$.id', '$.error_field');
+------+-------------------------------------------------+
| id | text |
+------+-------------------------------------------------+
| 2 | {"id": 2, "label": "sample2", "value": "test2"} |
| 1 | {"id": 1, "label": "sample", "value": "test"} |
| 3 | {"id": 3, "label": "sample3", "value": "test3"} |
+------+-------------------------------------------------+
3 rows in set (0.00 sec)
mysql> select * from sample where json_contains_path(`text`, 'all', '$.id', '$.error_field');
Empty set (0.00 sec)
JSON_VALUE
此函数需要mysql版本8.0及以上
从指定定路径处的JSON
文档中提取值,并返回提取的值,可以选择将其转换为所需的类型。
mysql> select JSON_VALUE(text,'$.value') from sample;
+----------------------------+
| JSON_VALUE(text,'$.value') |
+----------------------------+
| test2 |
| test |
| test3 |
+----------------------------+
3 rows in set (0.00 sec)
通过json_value
提取的字符串类型的值它会取消"
. json_value
相当于下面sql语句的组合形式.
SELECT CAST( JSON_UNQUOTE( JSON_EXTRACT(_json_doc_, _path_) ) AS _type_ );
如果想快速的取字符串的字面值,可以使用快捷语法. json->>path
形式。
mysql> select text->>'$.value' from sample;
+------------------+
| text->>'$.value' |
+------------------+
| test2 |
| test |
| test3 |
+------------------+
3 rows in set (0.01 sec)