MySQL JSON 数据需要 SQL 查询以根据对象中的键值对对象数组进行排序
MySQL JSON Data Need SQL Query to Sort Array of Objects Order based on key value in object
我有一个名为 posts
的 table 列 id, title, tags
.
CREATE TABLE IF NOT EXISTS `posts` (
`id` int(6) unsigned NOT NULL,
`title` varchar(100) NOT NULL,
`tags` json NOT NULL,
PRIMARY KEY (`id`)
) DEFAULT CHARSET=utf8;
在tags
字段中存储类似[{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}]
的数据。
INSERT INTO `posts` (`id`, `title`, `tags`) VALUES
('1', 'First Post', '[{"tag": "andoroid", "time": 123}, {"tag": "mobiles", "time": 432} ]'),
('2', 'Second Post', '[{"tag": "apple", "time": 125}]'),
('3', 'Third Post', '[{"tag": "android", "time": 124}]'),
('4', 'Fourth Post', '[{"tag": "mobiles", "time": 472}, {"tag": "android", "time": 129}]'),
('5', 'Fifth Post', '[{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}]'),
('6', 'Sixth Post', '[{"tag": "mobiles", "time": 121}, {"tag": "apple", "time": 120}]'),
('7', 'Seventh Post', '[{"tag": "apple", "time": 120}, {"tag": "mobiles", "time": 130}]'),
('8', 'Eigth Post', '[{"tag": "android", "time": 126}]'),
('9', 'Nineth Post', '[{"tag": "mobiles", "time":132}]');
正在根据标签值过滤 table 中的数据,例如。 tag == "android"
。为此,我正在使用 mysql 查询
SELECT id, title, tags FROM posts where JSON_CONTAINS(
tags , '{"tag": "android"}'
) ;
它工作正常。数据库 Fiddle : https://www.db-fiddle.com/f/5Hw1FyL3Qv2RLtCw4tZbyh/1
此外,我需要根据标签中的 time
值对结果进行排序。 tag == 'android' and order by time
。
在此先感谢您的帮助。
在 8 之前的 MySQL 版本中解决此问题的唯一方法是使用存储函数从每组标签中找到最小值 time
。像这样:
DELIMITER //
CREATE FUNCTION min_time(tags JSON)
RETURNS INT
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE mint INT DEFAULT 9999;
DECLARE thist INT;
SET thist = JSON_EXTRACT(tags, CONCAT('$[', i, '].time'));
WHILE thist IS NOT NULL DO
IF thist < mint THEN
SET mint = thist;
END IF;
SET i = i + 1;
SET thist = JSON_EXTRACT(tags, CONCAT('$[', i, '].time'));
END WHILE;
RETURN mint;
END //
然后你可以使用这样的查询:
SELECT id, title, tags, min_time(tags) AS min_time
FROM posts
WHERE JSON_CONTAINS(tags , '{"tag": "android"}')
ORDER BY min_time
输出:
id title tags tags->'$[*].time' min_time
4 Fourth Post [{"tag": "mobiles", "time": 472}, {"tag": "android", "time": 121}] [472, 121] 121
5 Fifth Post [{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}] [122, 140] 122
3 Third Post [{"tag": "android", "time": 124}] [124] 124
8 Eigth Post [{"tag": "android", "time": 126}] [126] 126
这可能是过度设计的,因为它按 post 上任何标签的最短时间排序。如果您 仅 想按与 android
标签(您正在搜索的标签)关联的时间排序,您可以使用此简化查询:
SELECT id, title, tags,
JSON_EXTRACT(tags, CONCAT(SUBSTRING_INDEX(JSON_UNQUOTE(JSON_SEARCH(tags, 'one', 'android')), '.', 1), '.time')) AS tag_time
FROM posts
WHERE JSON_CONTAINS(tags , '{"tag": "android"}')
ORDER BY tag_time
输出:
id title tags tag_time
3 Third Post [{"tag": "android", "time": 75}] 75
4 Fourth Post [{"tag": "mobiles", "time": 472}, {"tag": "android", "time": 121}] 121
5 Fifth Post [{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}] 122
8 Eigth Post [{"tag": "android", "time": 126}] 126
我有一个名为
posts
的 table 列id, title, tags
.CREATE TABLE IF NOT EXISTS `posts` ( `id` int(6) unsigned NOT NULL, `title` varchar(100) NOT NULL, `tags` json NOT NULL, PRIMARY KEY (`id`) ) DEFAULT CHARSET=utf8;
在
tags
字段中存储类似[{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}]
的数据。INSERT INTO `posts` (`id`, `title`, `tags`) VALUES ('1', 'First Post', '[{"tag": "andoroid", "time": 123}, {"tag": "mobiles", "time": 432} ]'), ('2', 'Second Post', '[{"tag": "apple", "time": 125}]'), ('3', 'Third Post', '[{"tag": "android", "time": 124}]'), ('4', 'Fourth Post', '[{"tag": "mobiles", "time": 472}, {"tag": "android", "time": 129}]'), ('5', 'Fifth Post', '[{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}]'), ('6', 'Sixth Post', '[{"tag": "mobiles", "time": 121}, {"tag": "apple", "time": 120}]'), ('7', 'Seventh Post', '[{"tag": "apple", "time": 120}, {"tag": "mobiles", "time": 130}]'), ('8', 'Eigth Post', '[{"tag": "android", "time": 126}]'), ('9', 'Nineth Post', '[{"tag": "mobiles", "time":132}]');
正在根据标签值过滤 table 中的数据,例如。
tag == "android"
。为此,我正在使用 mysql 查询SELECT id, title, tags FROM posts where JSON_CONTAINS( tags , '{"tag": "android"}' ) ;
它工作正常。数据库 Fiddle : https://www.db-fiddle.com/f/5Hw1FyL3Qv2RLtCw4tZbyh/1
此外,我需要根据标签中的 time
值对结果进行排序。 tag == 'android' and order by time
。
在此先感谢您的帮助。
在 8 之前的 MySQL 版本中解决此问题的唯一方法是使用存储函数从每组标签中找到最小值 time
。像这样:
DELIMITER //
CREATE FUNCTION min_time(tags JSON)
RETURNS INT
BEGIN
DECLARE i INT DEFAULT 0;
DECLARE mint INT DEFAULT 9999;
DECLARE thist INT;
SET thist = JSON_EXTRACT(tags, CONCAT('$[', i, '].time'));
WHILE thist IS NOT NULL DO
IF thist < mint THEN
SET mint = thist;
END IF;
SET i = i + 1;
SET thist = JSON_EXTRACT(tags, CONCAT('$[', i, '].time'));
END WHILE;
RETURN mint;
END //
然后你可以使用这样的查询:
SELECT id, title, tags, min_time(tags) AS min_time
FROM posts
WHERE JSON_CONTAINS(tags , '{"tag": "android"}')
ORDER BY min_time
输出:
id title tags tags->'$[*].time' min_time
4 Fourth Post [{"tag": "mobiles", "time": 472}, {"tag": "android", "time": 121}] [472, 121] 121
5 Fifth Post [{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}] [122, 140] 122
3 Third Post [{"tag": "android", "time": 124}] [124] 124
8 Eigth Post [{"tag": "android", "time": 126}] [126] 126
这可能是过度设计的,因为它按 post 上任何标签的最短时间排序。如果您 仅 想按与 android
标签(您正在搜索的标签)关联的时间排序,您可以使用此简化查询:
SELECT id, title, tags,
JSON_EXTRACT(tags, CONCAT(SUBSTRING_INDEX(JSON_UNQUOTE(JSON_SEARCH(tags, 'one', 'android')), '.', 1), '.time')) AS tag_time
FROM posts
WHERE JSON_CONTAINS(tags , '{"tag": "android"}')
ORDER BY tag_time
输出:
id title tags tag_time
3 Third Post [{"tag": "android", "time": 75}] 75
4 Fourth Post [{"tag": "mobiles", "time": 472}, {"tag": "android", "time": 121}] 121
5 Fifth Post [{"tag": "android", "time": 122}, {"tag": "apple", "time": 140}] 122
8 Eigth Post [{"tag": "android", "time": 126}] 126