如何根据某些条件从 mysql 的 JSON 数组字段 select JSON 对象
How to select JSON object from JSON array field of mysql by some condition
我有一个 table 和 JSON 字段,其中包含一个 JSON 对象数组。我需要 select 某些条件下的对象。
创建并填写 table:
CREATE TABLE test (
id INT AUTO_INCREMENT PRIMARY KEY,
json_list JSON
);
INSERT INTO test(json_list) VALUES
("{""list"": [{""type"": ""color"", ""value"": ""red""}, {""type"": ""shape"", ""value"": ""oval""}, {""type"": ""color"", ""value"": ""green""}]}"),
("{""list"": [{""type"": ""shape"", ""value"": ""rect""}, {""type"": ""color"", ""value"": ""olive""}]}"),
("{""list"": [{""type"": ""color"", ""value"": ""red""}]}")
;
现在我需要 select 所有行中 type
= color
的所有对象。
我想看到这个输出:
id extracted_value
1 {"type": "color", "value": "red"}
1 {"type": "color", "value": "green"}
2 {"type": "color", "value": "olive"}
3 {"type": "color", "value": "red"}
如果也能得到这个就好了:
id color
1 red
1 green
2 olive
3 red
我无法更改数据库或 JSON。
我正在使用 MySQL 5.7
我目前的解决方案
我的解决方案是交叉连接 table 和一些索引集,然后提取 JSON 数组的所有元素。
我不喜欢它,因为好像一个数组中可能的对象数很大,所以要求所有索引都达到最大值。它使查询变慢,因为它不会在到达数组末尾时停止计算 JSON 值。
SELECT
test.id,
JSON_EXTRACT(test.json_list, CONCAT('$.list[', ind.ind, ']')),
ind.ind
FROM
test
CROSS JOIN
(SELECT 0 AS ind UNION ALL SELECT 1 AS ind UNION ALL SELECT 2 AS ind) ind
WHERE
JSON_LENGTH(json_list, "$.list") > ind.ind
AND JSON_EXTRACT(json_list, CONCAT('$.list[', ind.ind, '].type')) = "color";
通过更改JSON_EXTRACT
路径很容易只获取值。但是有没有更好的方法呢?
编辑
- 添加了 json_list.list 长度检查。在这种情况下,这过滤掉了 67% 的派生 table 行。
所以目前最好的解决方案是我的:
SELECT
test.id,
JSON_EXTRACT(test.json_list, CONCAT('$.list[', ind.ind, ']')),
ind.ind
FROM
test
CROSS JOIN
(SELECT 0 AS ind UNION ALL SELECT 1 AS ind UNION ALL SELECT 2 AS ind) ind
WHERE
JSON_LENGTH(json_list, "$.list") > ind.ind
AND JSON_EXTRACT(json_list, CONCAT('$.list[', ind.ind, '].type')) = "color";
SELECT JSON_EXTRACT(json_list, '$.list[*]')
FROM `test`
where JSON_CONTAINS(json_list, '{"type":"color"}', '$.list')
我有一个 table 和 JSON 字段,其中包含一个 JSON 对象数组。我需要 select 某些条件下的对象。
创建并填写 table:
CREATE TABLE test (
id INT AUTO_INCREMENT PRIMARY KEY,
json_list JSON
);
INSERT INTO test(json_list) VALUES
("{""list"": [{""type"": ""color"", ""value"": ""red""}, {""type"": ""shape"", ""value"": ""oval""}, {""type"": ""color"", ""value"": ""green""}]}"),
("{""list"": [{""type"": ""shape"", ""value"": ""rect""}, {""type"": ""color"", ""value"": ""olive""}]}"),
("{""list"": [{""type"": ""color"", ""value"": ""red""}]}")
;
现在我需要 select 所有行中 type
= color
的所有对象。
我想看到这个输出:
id extracted_value
1 {"type": "color", "value": "red"}
1 {"type": "color", "value": "green"}
2 {"type": "color", "value": "olive"}
3 {"type": "color", "value": "red"}
如果也能得到这个就好了:
id color
1 red
1 green
2 olive
3 red
我无法更改数据库或 JSON。
我正在使用 MySQL 5.7
我目前的解决方案
我的解决方案是交叉连接 table 和一些索引集,然后提取 JSON 数组的所有元素。
我不喜欢它,因为好像一个数组中可能的对象数很大,所以要求所有索引都达到最大值。它使查询变慢,因为它不会在到达数组末尾时停止计算 JSON 值。
SELECT
test.id,
JSON_EXTRACT(test.json_list, CONCAT('$.list[', ind.ind, ']')),
ind.ind
FROM
test
CROSS JOIN
(SELECT 0 AS ind UNION ALL SELECT 1 AS ind UNION ALL SELECT 2 AS ind) ind
WHERE
JSON_LENGTH(json_list, "$.list") > ind.ind
AND JSON_EXTRACT(json_list, CONCAT('$.list[', ind.ind, '].type')) = "color";
通过更改JSON_EXTRACT
路径很容易只获取值。但是有没有更好的方法呢?
编辑
- 添加了 json_list.list 长度检查。在这种情况下,这过滤掉了 67% 的派生 table 行。
所以目前最好的解决方案是我的:
SELECT
test.id,
JSON_EXTRACT(test.json_list, CONCAT('$.list[', ind.ind, ']')),
ind.ind
FROM
test
CROSS JOIN
(SELECT 0 AS ind UNION ALL SELECT 1 AS ind UNION ALL SELECT 2 AS ind) ind
WHERE
JSON_LENGTH(json_list, "$.list") > ind.ind
AND JSON_EXTRACT(json_list, CONCAT('$.list[', ind.ind, '].type')) = "color";
SELECT JSON_EXTRACT(json_list, '$.list[*]')
FROM `test`
where JSON_CONTAINS(json_list, '{"type":"color"}', '$.list')