mysql handles fields in json format, and understands mysql parsing json data in one article

Article directory

I. Overview

1. What is JSON

slightly. Baidu by itself.

2. MySQL JSON

The JSON data type is supported since MySQL 5.7.8. Previously, JSON documents could only be saved with character types (CHAR, VARCHAR or TEXT).

MySQL 8.0 version adds index support for JSON type. You can use the CREATE INDEX statement to create JSON-type indexes to improve query efficiency for JSON-type data.

The space required to store a JSON document is roughly the same as the space required to store a LONGBLOB or LONGTEXT.

Prior to MySQL 8.0.13, JSON columns could not have a non-null default value.

The JSON type is more suitable for storing some data whose columns are not fixed, less modified, and relatively static. After MySQL supports data in JSON format, it can reduce the dependence on non-relational databases.

3. The difference between varchar, text, and json type fields

These three types of fields can all be stored in json format, and it seems that normal json functions can also be used when querying. Is there any difference between the three types of data stored in json?

Let's test it next.

Second, the creation of JSON type

1. Designation of table creation

CREATE TABLE `users` (
  `id` int NOT NULL AUTO_INCREMENT COMMENT 'id',
  `name` varchar(50) DEFAULT NULL COMMENT '名字',
  `json_data` json DEFAULT NULL COMMENT 'json数据',
  `info` varchar(2000) DEFAULT NULL COMMENT '普通数据',
  `text` text COMMENT 'text数据',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

2. Modify the field

-- 添加json字段
ALTER TABLE users ADD COLUMN `test_json` JSON DEFAULT NULL COMMENT '测试';
-- 修改字段类型为json
ALTER TABLE users modify test_json JSON DEFAULT NULL COMMENT '测试';
-- 删除json字段
ALTER TABLE users DROP COLUMN test_json;

3. Insertion of JSON type

1. Insert string directly

Varchar, text, and json formats are all supported, and more complex nested json can also be inserted:

-- 插入数组
insert into users(json_data) values('[1, "abc", null, true, "08:45:06.000000"]');
insert into users(info) values('[1, "abc", null, true, "08:45:06.000000"]');
insert into users(text) values('[1, "abc", null, true, "08:45:06.000000"]');
-- 插入对象
insert into users(json_data) values('{"id": 87, "name": "carrot"}');
insert into users(info) values('{"id": 87, "name": "carrot"}');
insert into users(text) values('{"id": 87, "name": "carrot"}');
-- 插入嵌套json
insert into users(json_data) values('[{"sex": "M"},{"sex":"F", "city":"nanjing"}]');
insert into users(info) values('[{"sex": "M"},{"sex":"F", "city":"nanjing"}]');
insert into users(text) values('[{"sex": "M"},{"sex":"F", "city":"nanjing"}]');

However, for fields in json format, the format will be automatically verified when inserted. If the format is not json, an error will be reported:

insert into users(json_data) values('{"id", "name": "carrot"}');
> 3140 - Invalid JSON text: "Missing a colon after a name of object member." at position 5 in value for column 'users.json_data'.

2. The JSON_ARRAY() function inserts an array

-- 格式:
JSON_ARRAY([val[, val] ...])

-- 使用JSON_ARRAY()函数创建数组 : [1, "abc", null, true, "08:09:38.000000"]
insert into users(json_data) values(JSON_ARRAY(1, "abc", null, true,curtime()));
insert into users(info) values(JSON_ARRAY(1, "abc", null, true,curtime()));
insert into users(text) values(JSON_ARRAY(1, "abc", null, true,curtime()));

3. The JSON_OBJECT() function inserts an object

For JSON documents, KEY names cannot be repeated.

If there are duplicate KEYs in the inserted value, before MySQL 8.0.3, following the principle of first duplicate key wins, the first KEY will be kept, and the latter will be discarded.

Starting from MySQL 8.0.3, the last duplicate key wins principle is followed, and only the last KEY will be kept.

-- 格式:
JSON_OBJECT([key, val[, key, val] ...])

-- 创建对象,一个key对应一个value : {"id": 87, "name": "carrot"}
insert into users(json_data) values(json_object('id', 87, 'name', 'carrot'));
insert into users(info) values(json_object('id', 87, 'name', 'carrot'));
insert into users(text) values(json_object('id', 87, 'name', 'carrot'));

4. JSON_ARRAYAGG() and JSON_OBJECTAGG() encapsulate query results into json

mysql> SELECT o_id, attribute, value FROM t3;
+------+-----------+-------+
| o_id | attribute | value |
+------+-----------+-------+
|    2 | color     | red   |
|    2 | fabric    | silk  |
|    3 | color     | green |
|    3 | shape     | square|
+------+-----------+-------+
4 rows in set (0.00 sec)

mysql> SELECT o_id, JSON_ARRAYAGG(attribute) AS attributes
    -> FROM t3 GROUP BY o_id;
+------+---------------------+
| o_id | attributes          |
+------+---------------------+
|    2 | ["color", "fabric"] |
|    3 | ["color", "shape"]  |
+------+---------------------+
2 rows in set (0.00 sec)
mysql> SELECT o_id, attribute, value FROM t3;
+------+-----------+-------+
| o_id | attribute | value |
+------+-----------+-------+
|    2 | color     | red   |
|    2 | fabric    | silk  |
|    3 | color     | green |
|    3 | shape     | square|
+------+-----------+-------+
4 rows in set (0.00 sec)

mysql> SELECT o_id, JSON_OBJECTAGG(attribute, value)
    -> FROM t3 GROUP BY o_id;
+------+---------------------------------------+
| o_id | JSON_OBJECTAGG(attribute, value)      |
+------+---------------------------------------+
|    2 | {
   
   "color": "red", "fabric": "silk"}    |
|    3 | {
   
   "color": "green", "shape": "square"} |
+------+---------------------------------------+
2 rows in set (0.00 sec)

4. Analysis of JSON type

1, JSON_EXTRACT() parse json

Format: JSON_EXTRACT(json_doc, path[, path] …)
where json_doc is the JSON document and path is the path. This function will extract the elements of the specified path (path) from the JSON document. If the specified path does not exist, NULL will be returned. Multiple paths can be specified, and multiple matched values ​​will be returned in an array.

-- 解析数组
-- 取下标为1的数组值(数组下标从0开始),结果:20
SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]');
-- 取多个,结果返回是一个数组,结果:[20, 10]
SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[1]', '$[0]');
-- 可以使用*获取全部,结果:[30, 40]
SELECT JSON_EXTRACT('[10, 20, [30, 40]]', '$[2][*]');

-- 还可通过 [M to N] 获取数组的子集
-- 结果:[10, 20]
select json_extract('[10, 20, [30, 40]]', '$[0 to 1]');
-- 这里的 last 代表最后一个元素的下标,结果:[20, [30, 40]]
select json_extract('[10, 20, [30, 40]]', '$[last-1 to last]');
-- 解析对象:对象的路径是通过 KEY 来表示的。
set @j='{"a": 1, "b": [2, 3], "a c": 4}';

-- 如果 KEY 在路径表达式中不合法(譬如存在空格),则在引用这个 KEY 时,需用双引号括起来。
-- 结果: 1 4 3
select json_extract(@j, '$.a'), json_extract(@j, '$."a c"'), json_extract(@j, '$.b[1]');
-- 使用*获取所有元素,结果:[1, [2, 3], 4]
select json_extract('{"a": 1, "b": [2, 3], "a c": 4}', '$.*');
-- 这里的 $**.b 匹配 $.a.b 和 $.c.b,结果:[1, 2]
select json_extract('{"a": {"b": 1}, "c": {"b": 2}}', '$**.b');

json_extract解析出来的数据,可以灵活用于where、order by等等所有地方。

2. -> Arrow function parsing json

column->path, including column->>path mentioned later, is syntactic sugar, which will be automatically converted to JSON_EXTRACT at the bottom layer when actually used.

column->path is equivalent to JSON_EXTRACT(column, path), only one path can be specified.

-- 同JSON_EXTRACT
insert into users(json_data) values('{"empno": 1001, "ename": "jack"}');
-- 结果:"jack"
select json_data, json_data -> '$.ename' from users;

3. JSON_QUOTE() reference and JSON_UNQUOTE() dereference

JSON_QUOTE(string), generate a valid JSON string, mainly to escape some special characters (such as double quotes).

-- 结果:"null"	"\"null\""	"[1, 2, 3]"
select json_quote('null'), json_quote('"null"'), json_quote('[1, 2, 3]');

JSON_UNQUOTE(json_val), convert JSON to string output. It is often used to remove quotes after parsing with JSON_EXTRACT() and -> functions.
JSON_UNQUOTE() special character escape table:

escape sequence the character represented by the sequence
\" Double quotes
\b backspace character
\f form feed character
\n line break
\r carriage return
\t Tabs
\\ backslash (\) character
\uXXXX Unicode XXXX to UTF-8
insert into users(json_data) values('{"empno": 1001, "ename": "jack"}');
-- 字符串类型转换后会去掉引号,结果:"jack"	jack	1	0
select json_data->'$.ename',json_unquote(json_data->'$.ename'),json_valid(json_data->'$.ename'),json_valid(json_unquote(json_data->'$.ename')) from users;
-- 数字类型转换并没有额外效果,结果:1001	1001	1	1
select json_data->'$.empno',json_unquote(json_data->'$.empno'),json_valid(json_data->'$.empno'),json_valid(json_unquote(json_data->'$.empno')) from users;

Intuitively, if JSON_UNQUOTE is not added, the string will be surrounded by double quotes, but if JSON_UNQUOTE is added, it will not. But in essence, the former is the STRING type in JSON, and the latter is the character type in MySQL, which can be judged by JSON_VALID.

4. ->>Arrow parsing json

Similar to column->path, except that it returns a string, which is equivalent to removing the double quotes of the string, which is a syntactic sugar, essentially executing JSON_UNQUOTE( JSON_EXTRACT(column, path) ).

The following three are equivalent:
JSON_UNQUOTE( JSON_EXTRACT(column, path) )
JSON_UNQUOTE(column -> path)
column->>path

insert into users(json_data) values('{"empno": 1001, "ename": "jack"}');
-- 结果:"jack"	jack	jack	jack
select json_data->'$.ename',json_unquote(json_data->'$.ename'),json_data->>'$.ename', JSON_UNQUOTE( JSON_EXTRACT(json_data, '$.ename') ) from users;

5. JSON type query

1. JSON_CONTAINS() determines whether it contains

Format: JSON_CONTAINS(target, candidate[, path])
to determine whether the target document contains a candidate document, return 1 if it is included, and return 0 if it is not included.
If path is included, determine whether the data in path is equal to candidate, and return 1 if it is equal. Return 0 if not equal

函数前加not可取反

SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
SET @j2 = '{"a":1}';
-- 判断@j中是否包含@j2,结果:1
SELECT JSON_CONTAINS(@j, @j2);

SET @j2 = '1';
-- 判断@j字段中的a是否等于1,结果:1
SELECT JSON_CONTAINS(@j, @j2, '$.a');
-- 结果:0
SELECT JSON_CONTAINS(@j, @j2, '$.b');

SET @j2 = '{"d": 4}';
-- 结果:0
SELECT JSON_CONTAINS(@j, @j2, '$.a');
-- 结果:1
SELECT JSON_CONTAINS(@j, @j2, '$.c');

SET @j = '[1, "a", 1.02]';
SET @j2 = '"a"';
-- 判断@j数组中是否包含@j2,结果:1
SELECT JSON_CONTAINS(@j, @j2);

2. JSON_CONTAINS_PATH() judgment

Format: JSON_CONTAINS_PATH(json_doc, one_or_all, path[, path] …)
Determines whether the specified path exists, if it exists, it returns 1, otherwise it returns 0.
The one_or_all in the function can specify one or all, one returns 1 if any path exists, and all returns 1 only if all paths exist.

函数前加not可取反

SET @j = '{"a": 1, "b": 2, "c": {"d": 4}}';
-- a或者e 存在一个就返回1,结果:1
SELECT JSON_CONTAINS_PATH(@j, 'one', '$.a', '$.e');
-- a和e都存在返回1,结果:0
SELECT JSON_CONTAINS_PATH(@j, 'all', '$.a', '$.e');
-- c中的d存在返回1,结果:1
SELECT JSON_CONTAINS_PATH(@j, 'one', '$.c.d');

SET @j = '[1, 4, "a", "c"]';
-- @j是一个数组,$[1]判断第二个数据是否存在,结果为1
select JSON_CONTAINS_PATH(@j, 'one', '$[1]');
-- $[11]判断第11个数据不存在,结果为0
select JSON_CONTAINS_PATH(@j, 'one', '$[11]');

3. JSON_KEYS() to get keys

Returns the outermost key of the JSON document. If a path is specified, returns the outermost key of the element corresponding to the path.

-- 结果:["a", "b"]
SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}');
-- 结果:["c"]
SELECT JSON_KEYS('{"a": 1, "b": {"c": 30}}', '$.b');

4. JSON_OVERLAPS() compares two json

Introduced in MySQL 8.0.17, it is used to compare whether two JSON documents have the same key-value pair or array element, and if so, return 1, otherwise 0. If both arguments are scalars, test whether the two scalars are equal.

函数前加not可取反

-- 结果: 1	0
select json_overlaps('[1,3,5,7]', '[2,5,7]'),json_overlaps('[1,3,5,7]', '[2,6,8]');

-- 部分匹配被视为不匹配,结果:0
SELECT JSON_OVERLAPS('[[1,2],[3,4],5]', '[1,[2,3],[4,5]]');

-- 比较对象时,如果它们至少有一个共同的键值对,则结果为真。
-- 结果:1
SELECT JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"c":1,"e":10,"f":1,"d":10}');
-- 结果:0
SELECT JSON_OVERLAPS('{"a":1,"b":10,"d":10}', '{"a":5,"e":10,"f":1,"d":20}');

-- 如果两个标量用作函数的参数,JSON_OVERLAPS()会执行一个简单的相等测试:
-- 结果:1
SELECT JSON_OVERLAPS('5', '5');
-- 结果:0
SELECT JSON_OVERLAPS('5', '6');

-- 当比较标量和数组时,JSON_OVERLAPS()试图将标量视为数组元素。在此示例中,第二个参数6被解释为[6],如下所示:结果:1
SELECT JSON_OVERLAPS('[4,5,6,7]', '6');

-- 该函数不执行类型转换:
-- 结果:0
SELECT JSON_OVERLAPS('[4,5,"6",7]', '6');
-- 结果:0
SELECT JSON_OVERLAPS('[4,5,6,7]', '"6"');

5. JSON_SEARCH() returns the position of the string

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

Returns the position of a string (search_str) in the JSON document, where
one_or_all: the number of matches, one matches only once, and all matches all. If more than one match is found, the result will be returned as an array.
search_str: substring, support fuzzy matching: % and _.
escape_char: escape character, if this parameter is left blank or NULL, the default escape character \ will be used.
path: Find the path.

SET @j = '["abc", [{"k": "10"}, "def"], {"x":"abc"}, {"y":"bcd"}]';
-- 结果:"$[0]"
SELECT JSON_SEARCH(@j, 'one', 'abc');
-- 结果:["$[0]", "$[2].x"]
SELECT JSON_SEARCH(@j, 'all', 'abc');
-- 结果:null
SELECT JSON_SEARCH(@j, 'all', 'ghi');
-- 结果:"$[1][0].k"
SELECT JSON_SEARCH(@j, 'all', '10');
-- 结果:"$[1][0].k"
SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$');
-- 结果:"$[1][0].k"
SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[*]');
-- 结果:"$[1][0].k"
SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$**.k');
-- 结果:"$[1][0].k"
SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[*][0].k');
-- 结果:"$[1][0].k"
SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[1]');
-- 结果:"$[1][0].k"
SELECT JSON_SEARCH(@j, 'all', '10', NULL, '$[1][0]');
-- 结果:"$[2].x"
SELECT JSON_SEARCH(@j, 'all', 'abc', NULL, '$[2]');
-- 结果:["$[0]", "$[2].x"]
SELECT JSON_SEARCH(@j, 'all', '%a%');
-- 结果:["$[0]", "$[2].x", "$[3].y"]
SELECT JSON_SEARCH(@j, 'all', '%b%');
-- 结果:"$[0]"
SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[0]');
-- 结果:"$[2].x"
SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[2]');
-- 结果:null
SELECT JSON_SEARCH(@j, 'all', '%b%', NULL, '$[1]');
-- 结果:null
SELECT JSON_SEARCH(@j, 'all', '%b%', '', '$[1]');
-- 结果:"$[3].y"
SELECT JSON_SEARCH(@j, 'all', '%b%', '', '$[3]');

6. JSON_VALUE() extracts the elements of the specified path

Format: JSON_VALUE(json_doc, path)
Introduced in 8.0.21, extract the elements of the specified path (path) from the JSON document.
The full syntax is as follows:

JSON_VALUE(json_doc, path [RETURNING type] [on_empty] [on_error])

on_empty:
    {
   
   NULL | ERROR | DEFAULT value} ON EMPTY

on_error:
    {
   
   NULL | ERROR | DEFAULT value} ON ERROR

Among them:
RETURNING type: the type of the return value, if not specified, the default is VARCHAR(512). If no character set is specified, the default is utf8mb4, which is case-sensitive.
on_empty: If the specified path has no value, the on_empty clause will be triggered. The default is to return NULL. You can also specify ERROR to throw an error, or return the default value through DEFAULT value.
on_error: The on_error clause will be triggered in three cases: when extracting elements from an array or object, multiple values ​​will be parsed; type conversion error, such as converting "abc" to unsigned type; value is truncate. The default is to return NULL.

-- 查找fname的值,结果为:Joe
SELECT JSON_VALUE('{"fname": "Joe", "lname": "Palmer"}', '$.fname');
-- 结果:49.95
SELECT JSON_VALUE('{"item": "shoes", "price": "49.95"}', '$.price' RETURNING DECIMAL(4,2)) AS price;
-- 结果:50.0
SELECT JSON_VALUE('{"item": "shoes", "price": "49.95"}', '$.price' RETURNING DECIMAL(4,1)) AS price;
-- 使用RETURNING定义返回数据类型,等效于以下sql:
SELECT CAST(
    JSON_UNQUOTE( JSON_EXTRACT(json_doc, path) )
    AS type
);


mysql> select json_value('{"item": "shoes", "price": "49.95"}', '$.price1' error on empty);
ERROR 3966 (22035): No value was found by 'json_value' on the specified path.

mysql> select json_value('[1, 2, 3]', '$[1 to 2]' error on error);
ERROR 3967 (22034): More than one value was found by 'json_value' on the specified path.

mysql> select json_value('{"item": "shoes", "price": "49.95"}', '$.item' returning unsigned error on error) as price;
ERROR 1690 (22003): UNSIGNED value is out of range in 'json_value'

7. MEMBER OF() judges whether it is an element in the json array

Format: value MEMBER OF (json_array)
The MEMBER OF() function was introduced in MySQL 8.0.17. Determine whether value is an element of the JSON array, if yes, return 1, otherwise 0.

函数前加not可取反

-- 结果:1
SELECT 17 MEMBER OF('[23, "abc", 17, "ab", 10]');
-- 结果:1
SELECT 'ab' MEMBER OF('[23, "abc", 17, "ab", 10]');
-- 部分匹配不代表匹配
-- 结果:0
SELECT 7 MEMBER OF('[23, "abc", 17, "ab", 10]');
-- 结果:0
SELECT 'a' MEMBER OF('[23, "abc", 17, "ab", 10]');
-- 不执行字符串类型之间的相互转换:结果:0·0
SELECT 17 MEMBER OF('[23, "abc", "17", "ab", 10]'), "17" MEMBER OF('[23, "abc", 17, "ab", 10]')
-- 要将该操作符与本身是数组的值一起使用,必须将其显式转换为JSON数组。结果:1
SELECT CAST('[4,5]' AS JSON) MEMBER OF('[[3,4],[4,5]]');
-- 还可以使用JSON_ARRAY()函数执行必要的强制转换,如下所示: 结果:1
SELECT JSON_ARRAY(4,5) MEMBER OF('[[3,4],[4,5]]');

--转换,结果:1	1
SET @a = CAST('{"a":1}' AS JSON);
SET @b = JSON_OBJECT("b", 2);
SET @c = JSON_ARRAY(17, @b, "abc", @a, 23);
SELECT @a MEMBER OF(@c), @b MEMBER OF(@c);

8. JSON_DEPTH() gets the maximum depth of JSON

Syntax: JSON_DEPTH(json_doc)
returns the maximum depth of the JSON document. Returns NULL if the argument is NULL. An error will occur if the argument is not a valid JSON document.
For empty arrays, empty objects, and scalar values, its depth is 1.

-- 结果:1	1	1
SELECT JSON_DEPTH('{}'), JSON_DEPTH('[]'), JSON_DEPTH('true');
-- 结果:2	2
SELECT JSON_DEPTH('[10, 20]'), JSON_DEPTH('[[], {}]');
-- 结果:3
SELECT JSON_DEPTH('[10, {"a": 20}]');

9. JSON_LENGTH() to get the document length

Syntax: JSON_LENGTH(json_doc[, path])

Returns the length of the JSON document, and its calculation rules are as follows:
1. If it is a scalar value, its length is 1.
2. If it is an array, its length is the number of array elements.
3. If it is an object, its length is the number of object elements.
4. The length of nested data and nested objects is not included.

-- 结果:3
SELECT JSON_LENGTH('[1, 2, {"a": 3}]');
-- 结果:2
SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}');
-- 结果:1
SELECT JSON_LENGTH('{"a": 1, "b": {"c": 30}}', '$.b');

10. JSON_TYPE() to get the JSON type

Syntax: JSON_TYPE(json_val)
returns the type of JSON value.
An error will occur if the parameter is not a valid JSON value.

SET @j = '{"a": [10, true]}';
-- 结果:OBJECT
SELECT JSON_TYPE(@j);
-- 结果:ARRAY
SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a'));
-- 结果:INTEGER
SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[0]'));
-- 结果:BOOLEAN
SELECT JSON_TYPE(JSON_EXTRACT(@j, '$.a[1]'));
-- 结果:NULL
SELECT JSON_TYPE(NULL);
-- 结果:STRING
select json_type('"abc"');
-- 结果:DATETIME
select json_type(cast(now() as json));

JSON type: OBJECT (object), ARRAY (array), BOOLEAN (Boolean type), NULL
Numeric type: INTEGER (TINYINT, SMALLINT, MEDIUMINT, and INT and BIGINT scalars), DOUBLE (DOUBLE, FLOAT), DECIMAL (MySQL, DECIMAL)
Time type: DATETIME (DATETIME, TIMESTAMP), DATE, TIME
String type: STRING (CHAR, VARCHAR, TEXT, ENUM, SET)
Binary type: BLOB (BINARY, VARBINARY, BLOB, BIT)
Other types: OPAQUE

11. JSON_VALID() checks the JSON format

Syntax: JSON_VALID(val)
determines whether the given value is a valid JSON document.
函数前加not可取反

-- 结果:1
SELECT JSON_VALID('{"a": 1}');
-- 结果:0	1
SELECT JSON_VALID('hello'), JSON_VALID('"hello"');

6. Modification of JSON type

1. Full modification

Directly use the update statement to replace all the json data fields.

update users set json_data = '{"a":1}';

2. JSON_ARRAY_APPEND() appends elements to the array

Format: JSON_ARRAY_APPEND(json_doc, path, val[, path, val] …)
Append elements to the specified position of the array. If the specified path does not exist, it will not be added.
In MySQL 5.7, this function is named JSON_APPEND(). MySQL 8.0 no longer supports this name.

SET @j = '["a", ["b", "c"], "d"]';
-- 在数组第二个元素的数组中追加1,结果:["a", ["b", "c", 1], "d"]
SELECT JSON_ARRAY_APPEND(@j, '$[1]', 1);
-- 结果:[["a", 2], ["b", "c"], "d"]
SELECT JSON_ARRAY_APPEND(@j, '$[0]', 2);
-- 结果:["a", [["b", 3], "c"], "d"]
SELECT JSON_ARRAY_APPEND(@j, '$[1][0]', 3);
-- 多个参数,结果:[["a", 1], [["b", 2], "c"], "d"]
select json_array_append(@j, '$[0]', 1, '$[1][0]', 2, '$[3]', 3);

SET @j = '{"a": 1, "b": [2, 3], "c": 4}';
-- 往b中追加,结果:{"a": 1, "b": [2, 3, "x"], "c": 4}
SELECT JSON_ARRAY_APPEND(@j, '$.b', 'x');
-- 结果:{"a": 1, "b": [2, 3], "c": [4, "y"]}
SELECT JSON_ARRAY_APPEND(@j, '$.c', 'y');

SET @j = '{"a": 1}';
-- 结果:[{"a": 1}, "z"]
SELECT JSON_ARRAY_APPEND(@j, '$', 'z');

3. JSON_ARRAY_INSERT() inserts elements into the specified position of the array

Format: JSON_ARRAY_INSERT(json_doc, path, val[, path, val] …)
inserts elements into the specified position of the array.

SET @j = '["a", {"b": [1, 2]}, [3, 4]]';
-- 在下标1处添加元素x,结果:["a", "x", {"b": [1, 2]}, [3, 4]]
SELECT JSON_ARRAY_INSERT(@j, '$[1]', 'x');
-- 没有100个元素,在最后插入,结果: ["a", {"b": [1, 2]}, [3, 4], "x"]
SELECT JSON_ARRAY_INSERT(@j, '$[100]', 'x');
-- 结果:["a", {"b": ["x", 1, 2]}, [3, 4]]
SELECT JSON_ARRAY_INSERT(@j, '$[1].b[0]', 'x');
-- 结果:["a", {"b": [1, 2]}, [3, "y", 4]]
SELECT JSON_ARRAY_INSERT(@j, '$[2][1]', 'y');

-- 早期的修改会影响数组中后续元素的位置,因此同一个JSON_ARRAY_INSERT()调用中的后续路径应该考虑这一点。在最后一个示例中,第二个路径没有插入任何内容,因为在第一次插入之后,该路径不再匹配任何内容。
-- 结果:["x", "a", {"b": [1, 2]}, [3, 4]]
SELECT JSON_ARRAY_INSERT(@j, '$[0]', 'x', '$[2][1]', 'y');

4. JSON_INSERT() inserts new values

Format: JSON_INSERT(json_doc, path, val[, path, val] ...)
inserts the value of a key that does not exist, and does not modify the existing key.
The insert operation is performed only if the value at the specified location or at the specified KEY does not exist. In addition, if the specified path is an array subscript and json_doc is not an array, this function will first convert json_doc into an array, and then insert new values.

SET @j = '{ "a": 1, "b": [2, 3]}';
-- a已经存在则忽略,c不存在则添加,结果:{"a": 1, "b": [2, 3], "c": "[true, false]"}
SELECT JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]');
-- 上面插入的c是一个带引号的字符串,想要插入一个数组,必须进行转换,结果:{"a": 1, "b": [2, 3], "c": [true, false]}
SELECT JSON_INSERT(@j, '$.a', 10, '$.c', CAST('[true, false]' AS JSON));

-- 下标0位置已经有值了,不会插入,结果:1
select json_insert('1','$[0]',"10");
-- 结果:[1, "10"]
select json_insert('1','$[1]',"10");
-- 结果:["1", "2", "10"]
select json_insert('["1","2"]','$[2]',"10");

5. JSON_MERGE() merges json

Format: JSON_MERGE(json_doc, json_doc[, json_doc] ...)
Merge two or more JSON documents. Synonym for JSON_MERGE_PRESERVE(); deprecated in MySQL 8.0.3 and may be removed in a future release.
推荐使用JSON_MERGE_PRESERVE()

-- 结果:[1, 2, true, false]
SELECT JSON_MERGE('[1, 2]', '[true, false]');

6. JSON_MERGE_PATCH() merges json

Introduced in MySQL 8.0.3, it is used to merge multiple JSON documents. The merging rules are as follows:
1. If the two documents are not all JSON objects, the merged result is the second document.
2. If both documents are JSON objects and there is no KEY with the same name, the merged document includes all elements of the two documents. If there is a KEY with the same name, the value of the second document will overwrite the first.

-- 不是对象,结果:[true, false]
SELECT JSON_MERGE_PATCH('[1, 2]', '[true, false]');
-- 都是对象,结果:{"id": 47, "name": "x"}
SELECT JSON_MERGE_PATCH('{"name": "x"}', '{"id": 47}');
-- 都不是对象,取第二个,结果:true
SELECT JSON_MERGE_PATCH('1', 'true');
-- 第一个不是对象,取第二个 ,结果:{"id": 47}
SELECT JSON_MERGE_PATCH('[1, 2]', '{"id": 47}');
-- 第二个覆盖第一个,结果:{"a": 3, "b": 2, "c": 4}
SELECT JSON_MERGE_PATCH('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }');
-- 结果:{"a": 5, "b": 2, "c": 4, "d": 6}
SELECT JSON_MERGE_PATCH('{ "a": 1, "b":2 }','{ "a": 3, "c":4 }', '{ "a": 5, "d":6 }');
-- 第二个有null,会删除该key,结果:{"a": 1}
SELECT JSON_MERGE_PATCH('{"a":1, "b":2}', '{"b":null}');
-- 嵌套json也可以合并,结果:{"a": {"x": 1, "y": 2}}
SELECT JSON_MERGE_PATCH('{"a":{"x":1}}', '{"a":{"y":2}}');

注意区别于JSON_MERGE_PRESERVE

7. JSON_MERGE_PRESERVE() merges json

Introduced in MySQL 8.0.3 to replace JSON_MERGE. It is also used to merge documents, but the merge rules are different from JSON_MERGE_PATCH.
1. Among the two documents, as long as one document is an array, the other document will be merged into the array.
2. Both documents are JSON objects. If there is a KEY with the same name, the second document will not overwrite the first one, but will append the value to the first document.

-- 数组合并,结果:[1, 2, true, false]
SELECT JSON_MERGE_PRESERVE('[1, 2]', '[true, false]');
-- 对象合并,结果:{"id": 47, "name": "x"}
SELECT JSON_MERGE_PRESERVE('{"name": "x"}', '{"id": 47}');
-- 两个常量,合并为一个数组,结果:[1, true]
SELECT JSON_MERGE_PRESERVE('1', 'true');
-- 对象合并到数组中,结果:[1, 2, {"id": 47}]
SELECT JSON_MERGE_PRESERVE('[1, 2]', '{"id": 47}');
-- 相同的key合并到一个数组,结果:{"a": [1, 3], "b": 2, "c": 4}
SELECT JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }', '{ "a": 3, "c": 4 }');
-- 结果:{"a": [1, 3, 5], "b": 2, "c": 4, "d": 6} 
SELECT JSON_MERGE_PRESERVE('{ "a": 1, "b": 2 }','{ "a": 3, "c": 4 }', '{ "a": 5, "d": 6 }');

注意区别于JSON_MERGE_PATCH()

8. JSON_REMOVE() deletes elements

Format: JSON_REMOVE(json_doc, path[, path] ...)
deletes the element at the specified position in the JSON document.

SET @j = '["a", ["b", "c"], "d"]';
-- 删除下标为1的元素,结果:["a", "d"]
SELECT JSON_REMOVE(@j, '$[1]');

set @j = '{ "a": 1, "b": [2, 3]}';
-- 删除a元素,结果:{"b": [2, 3]}
select json_remove(@j, '$.a');

set @j = '["a", ["b", "c"], "d", "e"]';
-- 删除多个元素,删除1下标之后,下标移动结果之后再删除下标2位置,结果:["a", "d"]
select json_remove(@j, '$[1]','$[2]');
-- 结果:["a", "e"]
select json_remove(@j, '$[1]','$[1]');

9. JSON_REPLACE() replaces elements

Syntax: JSON_REPLACE(json_doc, path, val[, path, val] …)
replaces existing values. Values ​​that do not exist have no effect.

SET @j = '{ "a": 1, "b": [2, 3]}';
-- 对象替换,结果:{"a": 10, "b": [2, 3]}
SELECT JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]');

-- 数组替换,结果:[1, "a", 4, "b"]
select json_replace('[1, "a", 3, "b"]', '$[2]', 4, '$[8]', 8);

10. JSON_SET() insert and replace

Format: JSON_SET(json_doc, path, val[, path, val] ...)
inserts new values ​​and replaces existing values.
In other words, if the specified location or value of the specified KEY does not exist, an insert operation will be performed, and if it exists, an update operation will be performed.

Note the difference between JSON_SET, JSON_INSERT, and JSON_REPLACE.

SET @j = '{ "a": 1, "b": [2, 3]}';
-- 结果:{"a": 10, "b": [2, 3], "c": "[true, false]"}
SELECT JSON_SET(@j, '$.a', 10, '$.c', '[true, false]');
-- 结果:{"a": 1, "b": [2, 3], "c": "[true, false]"}
SELECT JSON_INSERT(@j, '$.a', 10, '$.c', '[true, false]');
-- 结果:{"a": 10, "b": [2, 3]}
SELECT JSON_REPLACE(@j, '$.a', 10, '$.c', '[true, false]');

7. Other JSON functions

1. JSON_TABLE() column transfer

Syntax: JSON_TABLE(expr, path COLUMNS (column_list) [AS] alias)
MySQL 8.0 supports such a function, JSON_TABLE(), which extracts data from a JSON document and returns it in the form of a table.

The full syntax is as follows:

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

column_list:
    column[, column][, ...]

column:
    name FOR ORDINALITY
    |  name type PATH string path [on_empty] [on_error]
    |  name type EXISTS PATH string path
    |  NESTED [PATH] path COLUMNS (column_list)

on_empty:
    {
   
   NULL | DEFAULT json_string | ERROR} ON EMPTY

on_error:
    {
   
   NULL | DEFAULT json_string | ERROR} ON ERROR
mysql> SELECT *
    ->   FROM
    ->     JSON_TABLE(
    ->       '[ {"c1": null} ]',
    ->       '$[*]' COLUMNS( c1 INT PATH '$.c1' ERROR ON ERROR )
    ->     ) as jt;
+------+
| c1   |
+------+
| NULL |
+------+
1 row in set (0.00 sec)
select *
 from
   json_table(
     '[{"x":2, "y":"8", "z":9, "b":[1,2,3]}, {"x":"3", "y":"7"}, {"x":"4", "y":6, "z":10}]',
     "$[*]" columns(
       id for ordinality,
       xval varchar(100) path "$.x",
       yval varchar(100) path "$.y",
       z_exist int exists path "$.z",
       nested path '$.b[*]' columns (b INT PATH '$')
     )
   ) as t;
+------+------+------+---------+------+
| id   | xval | yval | z_exist | b    |
+------+------+------+---------+------+
|    1 | 2    | 8    |       1 |    1 |
|    1 | 2    | 8    |       1 |    2 |
|    1 | 2    | 8    |       1 |    3 |
|    2 | 3    | 7    |       0 | NULL |
|    3 | 4    | 6    |       1 | NULL |
+------+------+------+---------+------+
5 rows in set (0.00 sec)
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"a":"3"},{"a":2},{"b":1},{"a":0},{"a":[1,2]}]',
    ->     "$[*]"
    ->     COLUMNS(
    ->       rowid FOR ORDINALITY,
    ->       ac VARCHAR(100) PATH "$.a" DEFAULT '111' ON EMPTY DEFAULT '999' ON ERROR,
    ->       aj JSON PATH "$.a" DEFAULT '{"x": 333}' ON EMPTY,
    ->       bx INT EXISTS PATH "$.b"
    ->     )
    ->   ) AS tt;

+-------+------+------------+------+
| rowid | ac   | aj         | bx   |
+-------+------+------------+------+
|     1 | 3    | "3"        |    0 |
|     2 | 2    | 2          |    0 |
|     3 | 111  | {
   
   "x": 333} |    1 |
|     4 | 0    | 0          |    0 |
|     5 | 999  | [1, 2]     |    0 |
+-------+------+------------+------+
5 rows in set (0.00 sec)
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]',
    ->     "$[*]" COLUMNS(
    ->       xval VARCHAR(100) PATH "$.x",
    ->       yval VARCHAR(100) PATH "$.y"
    ->     )
    ->   ) AS  jt1;

+------+------+
| xval | yval |
+------+------+
| 2    | 8    |
| 3    | 7    |
| 4    | 6    |
+------+------+
-- 指定path
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"x":2,"y":"8"},{"x":"3","y":"7"},{"x":"4","y":6}]',
    ->     "$[1]" COLUMNS(
    ->       xval VARCHAR(100) PATH "$.x",
    ->       yval VARCHAR(100) PATH "$.y"
    ->     )
    ->   ) AS  jt1;

+------+------+
| xval | yval |
+------+------+
| 3    | 7    |
+------+------+
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[ {"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}, {"a":3}]',
    ->     '$[*]' COLUMNS(
    ->             a INT PATH '$.a',
    ->             NESTED PATH '$.b[*]' COLUMNS (b INT PATH '$')
    ->            )
    ->    ) AS jt
    -> WHERE b IS NOT NULL;

+------+------+
| a    | b    |
+------+------+
|    1 |   11 |
|    1 |  111 |
|    2 |   22 |
|    2 |  222 |
+------+------+
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"a": 1, "b": [11,111]}, {"a": 2, "b": [22,222]}]',
    ->     '$[*]' COLUMNS(
    ->         a INT PATH '$.a',
    ->         NESTED PATH '$.b[*]' COLUMNS (b1 INT PATH '$'),
    ->         NESTED PATH '$.b[*]' COLUMNS (b2 INT PATH '$')
    ->     )
    -> ) AS jt;

+------+------+------+
| a    | b1   | b2   |
+------+------+------+
|    1 |   11 | NULL |
|    1 |  111 | NULL |
|    1 | NULL |   11 |
|    1 | NULL |  111 |
|    2 |   22 | NULL |
|    2 |  222 | NULL |
|    2 | NULL |   22 |
|    2 | NULL |  222 |
+------+------+------+
mysql> SELECT *
    -> FROM
    ->   JSON_TABLE(
    ->     '[{"a": "a_val",
    '>       "b": [{
   
   "c": "c_val", "l": [1,2]}]},
    '>     {"a": "a_val",
    '>       "b": [{
   
   "c": "c_val","l": [11]}, {
   
   "c": "c_val", "l": [22]}]}]',
    ->     '$[*]' COLUMNS(
    ->       top_ord FOR ORDINALITY,
    ->       apath VARCHAR(10) PATH '$.a',
    ->       NESTED PATH '$.b[*]' COLUMNS (
    ->         bpath VARCHAR(10) PATH '$.c',
    ->         ord FOR ORDINALITY,
    ->         NESTED PATH '$.l[*]' COLUMNS (lpath varchar(10) PATH '$')
    ->         )
    ->     )
    -> ) as jt;

+---------+---------+---------+------+-------+
| top_ord | apath   | bpath   | ord  | lpath |
+---------+---------+---------+------+-------+
|       1 |  a_val  |  c_val  |    1 | 1     |
|       1 |  a_val  |  c_val  |    1 | 2     |
|       2 |  a_val  |  c_val  |    1 | 11    |
|       2 |  a_val  |  c_val  |    2 | 22    |
+---------+---------+---------+------+-------+

Query associated with the table:

CREATE TABLE t1 (c1 INT, c2 CHAR(1), c3 JSON);

INSERT INTO t1 () VALUES
	ROW(1, 'z', JSON_OBJECT('a', 23, 'b', 27, 'c', 1)),
	ROW(1, 'y', JSON_OBJECT('a', 44, 'b', 22, 'c', 11)),
	ROW(2, 'x', JSON_OBJECT('b', 1, 'c', 15)),
	ROW(3, 'w', JSON_OBJECT('a', 5, 'b', 6, 'c', 7)),
	ROW(5, 'v', JSON_OBJECT('a', 123, 'c', 1111))
;


SELECT c1, c2, JSON_EXTRACT(c3, '$.*') 
FROM t1 AS m 
JOIN 
JSON_TABLE(
  m.c3, 
  '$.*' 
  COLUMNS(
    at VARCHAR(10) PATH '$.a' DEFAULT '1' ON EMPTY, 
    bt VARCHAR(10) PATH '$.b' DEFAULT '2' ON EMPTY, 
    ct VARCHAR(10) PATH '$.c' DEFAULT '3' ON EMPTY
  )
) AS tt
ON m.c1 > tt.at;

Result:
insert image description here
Query associated with table:

CREATE TABLE employees (
  id INT,
  details JSON
);

INSERT INTO employees VALUES (1, '{"name": "John Doe", "position": "Manager"}');
INSERT INTO employees VALUES (2, '{"name": "Jane Smith", "position": "Developer"}');

SELECT name, position
FROM employees,
JSON_TABLE(details, '$' COLUMNS(
  name VARCHAR(255) PATH '$.name',
  position VARCHAR(255) PATH '$.position'
)) AS emp;

2. JSON_SCHEMA_VALID() validates json

Syntax: JSON_SCHEMA_VALID(schema,document)
determines whether the document (JSON document) meets the specification requirements defined by the schema (JSON object). For complete specification requirements, please refer to Draft 4 of the JSON Schema specification (https://json-schema.org/specification-links.html#draft-4). If not, the specific reason can be obtained through JSON_SCHEMA_VALIDATION_REPORT().

Its requirements are as follows:
1. document must be a JSON object.
2. The two required properties of a JSON object are latitude and longitude.
3. Latitude and longitude must be numeric types, and their sizes are between -90 ~ 90 and -180 ~ 180 respectively.

mysql> SET @schema = '{
    '>  "id": "http://json-schema.org/geo",
    '> "$schema": "http://json-schema.org/draft-04/schema#",
    '> "description": "A geographical coordinate",
    '> "type": "object",
    '> "properties": {
    '>   "latitude": {
    '>     "type": "number",
    '>     "minimum": -90,
    '>     "maximum": 90
    '>   },
    '>   "longitude": {
    '>     "type": "number",
    '>     "minimum": -180,
    '>     "maximum": 180
    '>   }
    '> },
    '> "required": ["latitude", "longitude"]
    '>}';
Query OK, 0 rows affected (0.01 sec)

mysql> SET @document = '{
    '> "latitude": 63.444697,
    '> "longitude": 10.445118
    '>}';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT JSON_SCHEMA_VALID(@schema, @document);
+---------------------------------------+
| JSON_SCHEMA_VALID(@schema, @document) |
+---------------------------------------+
|                                     1 |
+---------------------------------------+
1 row in set (0.00 sec)
mysql> SET @document = '{}';
mysql> SET @schema = '{
    '> "id": "http://json-schema.org/geo",
    '> "$schema": "http://json-schema.org/draft-04/schema#",
    '> "description": "A geographical coordinate",
    '> "type": "object",
    '> "properties": {
    '>   "latitude": {
    '>     "type": "number",
    '>     "minimum": -90,
    '>     "maximum": 90
    '>   },
    '>   "longitude": {
    '>     "type": "number",
    '>     "minimum": -180,
    '>     "maximum": 180
    '>   }
    '> }
    '>}';
Query OK, 0 rows affected (0.00 sec)


mysql> SELECT JSON_SCHEMA_VALID(@schema, @document);
+---------------------------------------+
| JSON_SCHEMA_VALID(@schema, @document) |
+---------------------------------------+
|                                     1 |
+---------------------------------------+
1 row in set (0.00 sec)

-- 建表指定check
mysql> CREATE TABLE geo (
    ->     coordinate JSON,
    ->     CHECK(
    ->         JSON_SCHEMA_VALID(
    ->             '{
    '>                 "type":"object",
    '>                 "properties":{
    '>                       "latitude":{
   
   "type":"number", "minimum":-90, "maximum":90},
    '>                       "longitude":{"type":"number", "minimum":-180, "maximum":180}
    '>                 },
    '>                 "required": ["latitude", "longitude"]
    '>             }',
    ->             coordinate
    ->         )
    ->     )
    -> );
Query OK, 0 rows affected (0.45 sec)

mysql> SET @point1 = '{
   
   "latitude":59, "longitude":18}';
Query OK, 0 rows affected (0.00 sec)

mysql> SET @point2 = '{
   
   "latitude":91, "longitude":0}';
Query OK, 0 rows affected (0.00 sec)

mysql> SET @point3 = '{
   
   "longitude":120}';
Query OK, 0 rows affected (0.00 sec)

mysql> INSERT INTO geo VALUES(@point1);
Query OK, 1 row affected (0.05 sec)

mysql> INSERT INTO geo VALUES(@point2);
ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated.

-- 查看原因
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Error
   Code: 3934
Message: The JSON document location '#/latitude' failed requirement 'maximum' at
JSON Schema location '#/properties/latitude'.
*************************** 2. row ***************************
  Level: Error
   Code: 3819
Message: Check constraint 'geo_chk_1' is violated.
2 rows in set (0.00 sec)


mysql> INSERT INTO geo VALUES(@point3);
ERROR 3819 (HY000): Check constraint 'geo_chk_1' is violated.
mysql> SHOW WARNINGS\G
*************************** 1. row ***************************
  Level: Error
   Code: 3934
Message: The JSON document location '#' failed requirement 'required' at JSON
Schema location '#'.
*************************** 2. row ***************************
  Level: Error
   Code: 3819
Message: Check constraint 'geo_chk_1' is violated.
2 rows in set (0.00 sec)

3. JSON_SCHEMA_VALIDATION_REPORT() to view the validation report

Syntax: JSON_SCHEMA_VALIDATION_REPORT(schema, document)
This function will return a report about the validation results in the form of a JSON document. If the verification is successful, return {"valid": true}. If the JSON document fails validation, the function will return a JSON object that contains the properties listed below:
valid: false
reason: reason for failure
schema-location: location where validation failed
document-location: location where validation failed
schema-failed-keyword : keyword or attribute name

mysql> SET @schema = '{
    '>  "id": "http://json-schema.org/geo",
    '> "$schema": "http://json-schema.org/draft-04/schema#",
    '> "description": "A geographical coordinate",
    '> "type": "object",
    '> "properties": {
    '>   "latitude": {
    '>     "type": "number",
    '>     "minimum": -90,
    '>     "maximum": 90
    '>   },
    '>   "longitude": {
    '>     "type": "number",
    '>     "minimum": -180,
    '>     "maximum": 180
    '>   }
    '> },
    '> "required": ["latitude", "longitude"]
    '>}';
Query OK, 0 rows affected (0.01 sec)

mysql> SET @document = '{
    '> "latitude": 63.444697,
    '> "longitude": 10.445118
    '>}';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document);
+---------------------------------------------------+
| JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) |
+---------------------------------------------------+
| {
   
   "valid": true}                                   |
+---------------------------------------------------+
1 row in set (0.00 sec)
mysql> SET @document = '{
    '> "latitude": 63.444697,
    '> "longitude": 310.445118
    '> }';

mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G
*************************** 1. row ***************************
JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): {
  "valid": false,
  "reason": "The JSON document location '#/longitude' failed requirement 'maximum' at JSON Schema location '#/properties/longitude'",
  "schema-location": "#/properties/longitude",
  "document-location": "#/longitude",
  "schema-failed-keyword": "maximum"
}
1 row in set (0.00 sec)

mysql> SET @document = '{}';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document))\G
*************************** 1. row ***************************
JSON_PRETTY(JSON_SCHEMA_VALIDATION_REPORT(@schema, @document)): {
  "valid": false,
  "reason": "The JSON document location '#' failed requirement 'required' at JSON Schema location '#'",
  "schema-location": "#",
  "document-location": "#",
  "schema-failed-keyword": "required"
}
1 row in set (0.00 sec)

mysql> SET @schema = '{
    '> "id": "http://json-schema.org/geo",
    '> "$schema": "http://json-schema.org/draft-04/schema#",
    '> "description": "A geographical coordinate",
    '> "type": "object",
    '> "properties": {
    '>   "latitude": {
    '>     "type": "number",
    '>     "minimum": -90,
    '>     "maximum": 90
    '>   },
    '>   "longitude": {
    '>     "type": "number",
    '>     "minimum": -180,
    '>     "maximum": 180
    '>   }
    '> }
    '>}';
Query OK, 0 rows affected (0.00 sec)

mysql> SELECT JSON_SCHEMA_VALIDATION_REPORT(@schema, @document);
+---------------------------------------------------+
| JSON_SCHEMA_VALIDATION_REPORT(@schema, @document) |
+---------------------------------------------------+
| {
   
   "valid": true}                                   |
+---------------------------------------------------+
1 row in set (0.00 sec)

4. JSON_PRETTY() formatted output

Syntax: JSON_PRETTY(json_val)
will format JSON output.

SELECT JSON_PRETTY('123'); # scalar
+--------------------+
| JSON_PRETTY('123') |
+--------------------+
| 123                |
+--------------------+

SELECT JSON_PRETTY("[1,3,5]"); # array
+------------------------+
| JSON_PRETTY("[1,3,5]") |
+------------------------+
| [
  1,
  3,
  5
]      |
+------------------------+

SELECT JSON_PRETTY('{"a":"10","b":"15","x":"25"}'); # object
+---------------------------------------------+
| JSON_PRETTY('{"a":"10","b":"15","x":"25"}') |
+---------------------------------------------+
| {
  "a": "10",
  "b": "15",
  "x": "25"
}   |
+---------------------------------------------+

SELECT JSON_PRETTY('["a",1,{"key1":
    "value1"},"5",     "77" ,
         {"key2":["value3","valueX",
    "valueY"]},"j", "2"   ]')\G  # nested arrays and objects
*************************** 1. row ***************************
JSON_PRETTY('["a",1,{"key1":
             "value1"},"5",     "77" ,
                {"key2":["value3","valuex",
          "valuey"]},"j", "2"   ]'): [
  "a",
  1,
  {
    "key1": "value1"
  },
  "5",
  "77",
  {
    "key2": [
      "value3",
      "valuex",
      "valuey"
    ]
  },
  "j",
  "2"
]

5. JSON_STORAGE_FREE() calculation space

New in MySQL 8.0, related to Partial Updates, used to calculate the remaining space of JSON documents after partial updates.

CREATE TABLE jtable (jcol JSON);
INSERT INTO jtable VALUES ('{"a": 10, "b": "wxyz", "c": "[true, false]"}');
-- 更新,结果:{"a": 10, "b": "wxyz", "c": 1}
UPDATE jtable SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wxyz", "$.c", 1);
-- 结果:14
SELECT JSON_STORAGE_FREE(jcol) FROM jtable;

-- 连续的部分更新对这个空闲空间的影响是累积的,如下例所示,使用JSON_SET()来减少具有键b的值所占用的空间(并且不做任何其他更改):
UPDATE jtable SET jcol = JSON_SET(jcol, "$.a", 10, "$.b", "wx", "$.c", 1);
-- 结果:16
SELECT JSON_STORAGE_FREE(jcol) FROM jtable;

-- 不使用JSON_SET()、JSON_REPLACE()或JSON_REMOVE()更新列意味着优化器不能就地执行更新;在这种情况下,JSON_STORAGE_FREE()返回0,如下所示:
UPDATE jtable SET jcol = '{"a": 10, "b": 1}';
-- 结果:0
SELECT JSON_STORAGE_FREE(jcol) FROM jtable;

-- JSON文档的部分更新只能在列值上执行。对于存储JSON值的用户变量,该值总是被完全替换,即使使用JSON_SET()执行更新也是如此:
SET @j = '{"a": 10, "b": "wxyz", "c": "[true, false]"}';
SET @j = JSON_SET(@j, '$.a', 10, '$.b', 'wxyz', '$.c', '1');
SELECT @j, JSON_STORAGE_FREE(@j) AS Free; -- 结果:0

-- 对于JSON文本,该函数总是返回0:
SELECT JSON_STORAGE_FREE('{"a": 10, "b": "wxyz", "c": "1"}') AS Free; -- 结果:0

6. JSON_STORAGE_SIZE() calculation space

Syntax: JSON_STORAGE_SIZE(json_val)
Introduced in MySQL 5.7.22, it is used to calculate the space usage of JSON documents.

CREATE TABLE jtable (jcol JSON);
INSERT INTO jtable VALUES ('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}');
SELECT jcol, JSON_STORAGE_SIZE(jcol) AS Size, JSON_STORAGE_FREE(jcol) AS Free FROM jtable;
+-----------------------------------------------+------+------+
| jcol                                          | Size | Free |
+-----------------------------------------------+------+------+
| {
   
   "a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"} |   47 |    0 |
+-----------------------------------------------+------+------+
1 row in set (0.00 sec)

UPDATE jtable SET jcol = '{"a": 4.55, "b": "wxyz", "c": "[true, false]"}';
SELECT jcol, JSON_STORAGE_SIZE(jcol) AS Size, JSON_STORAGE_FREE(jcol) AS Free FROM jtable;
+------------------------------------------------+------+------+
| jcol                                           | Size | Free |
+------------------------------------------------+------+------+
| {
   
   "a": 4.55, "b": "wxyz", "c": "[true, false]"} |   56 |    0 |
+------------------------------------------------+------+------+
1 row in set (0.00 sec)

-- json文本显示占用存储空间
SELECT JSON_STORAGE_SIZE('[100, "sakila", [1, 3, 5], 425.05]') AS A,
    JSON_STORAGE_SIZE('{"a": 1000, "b": "a", "c": "[1, 3, 5, 7]"}') AS B,
     JSON_STORAGE_SIZE('{"a": 1000, "b": "wxyz", "c": "[1, 3, 5, 7]"}') AS C,
     JSON_STORAGE_SIZE('[100, "json", [[10, 20, 30], 3, 5], 425.05]') AS D;
+----+----+----+----+
| A  | B  | C  | D  |
+----+----+----+----+
| 45 | 44 | 47 | 56 |
+----+----+----+----+
1 row in set (0.00 sec)

Eight, JSON field creation index

Like TEXT and BLOB fields, JSON fields do not allow direct creation of indexes.
Even if it is supported, it is of little practical significance, because we generally query based on the elements in the document, and rarely based on the entire JSON document.
To query the elements in the document, you need to use MySQL 5.7 虚拟列及函数索引.

# C2 即虚拟列
# index (c2) 对虚拟列添加索引。
create table t ( c1 json, c2 varchar(10) as (JSON_UNQUOTE(c1 -> "$.name")), index (c2) );

insert into t (c1) values  ('{"id": 1, "name": "a"}'), ('{"id": 2, "name": "b"}'), ('{"id": 3, "name": "c"}'), ('{"id": 4, "name": "d"}');

mysql> explain select * from t where c2 = 'a';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t     | NULL       | ref  | c2            | c2   | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from t where c1->'$.name' = 'a';
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref   | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
|  1 | SIMPLE      | t     | NULL       | ref  | c2            | c2   | 43      | const |    1 |   100.00 | NULL  |
+----+-------------+-------+------------+------+---------------+------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

It can be seen that no matter whether you use virtual columns or elements in the document to query, you can use the upper index.

Note that JSON_UNQUOTE needs to be specified when creating a virtual column to convert the return value of c1 -> "$.name" into a string.

reference documents

https://dev.mysql.com/doc/refman/8.0/en/json.html
https://blog.csdn.net/java_faep/article/details/125206014
https://zhuanlan.zhihu.com/p/514819634?utm_id=0
https://blog.csdn.net/sinat_20938225/article/details/129471550

GeoJSON: https://dev.mysql.com/doc/refman/8.0/en/spatial-geojson-functions.html
json method: https://dev.mysql.com/doc/refman/8.0/en/json- functions.html
json index: https://dev.mysql.com/doc/refman/8.0/en/create-table-secondary-indexes.html#json-column-indirect-index
json multivalued index: https:// dev.mysql.com/doc/refman/8.0/en/create-index.html#create-index-multi-valued

Guess you like

Origin blog.csdn.net/A_art_xiang/article/details/132472381