我需要从下面的mysql数据集中选择所有实现的值(= true)的SUM。在这个例子中,我应该只得到1000。
请注意,键是动态的(年\月\日)。
我可以通过运行以下sql来获取值列表:
SELECT (JSON_EXTRACT(json_value, "$**.value")) AS total FROM milestone
但是,我似乎无法使过滤器部分与此配合使用:
JSON_CONTAINS_PATH(json_value, 'all', "$**.realized") IS NOT NULL
id = 1,列json_value
{
"2018": {
"5": {
"4": {
"value": "5000"
}
},
"12": {
"4": {
"value": "80000",
"realized": "false"
}
}
}
}
id = 2,列json_value
{
"2016": {
"12": {
"4": {
"value": "1000",
"realized": "true"
}
}
}
}
答案 0 :(得分:1)
以下是可在MySQL 5.7上运行的查询:
SELECT SUM(
JSON_UNQUOTE(
JSON_EXTRACT(
json_value,
CONCAT(
SUBSTRING_INDEX(
JSON_UNQUOTE(JSON_SEARCH(json_value, 'all', 'true')), '.', 4),
'.value'
)
)
)
) AS sum
FROM milestone
WHERE SUBSTRING_INDEX(
JSON_UNQUOTE(JSON_SEARCH(json_value, 'all', 'true')),
'.', -1) = 'realized'
这是相当复杂的,并且难以开发和维护。同样,它可能无法处理在给定的JSON文档中有多个realized: true
条目的情况。或者,除了“ realized”以外,还有其他值为“ true”的JSON密钥。甚至想到边缘情况都将非常棘手,更不用说用代码处理它们了。
出于好奇,为什么不将这些数据存储为传统表?
CREATE TABLE milestone (
milestone_id INT NOT NULL,
date DATE NOT NULL,
value INT NOT NULL,
realized BOOL,
PRIMARY KEY (milestone_id, date)
);
INSERT INTO milestone VALUES
(1, '2018-05-04', 5000, NULL),
(1, '2018-12-04', 80000, false),
(2, '2016-12-04', 1000, true);
然后,您的查询会更简单:
SELECT SUM(value) FROM milestone WHERE realized = true;
我很好奇,因为我看到有更多的人在MySQL中使用JSON,而使用普通表和列会更容易。更容易编写查询,更易于理解查询,更有效地存储数据并优化查询性能。
按您的方式使用JSON会使查询比原本要困难得多。
答案 1 :(得分:0)
在现代版本的MySQL(> = 8.0.4)中,查询相对简单(请参见JSON_TABLE):
SELECT
`milestone`.`id`,
SUM(`der`.`value`) `total`
FROM
`milestone`,
JSON_TABLE(
JSON_ARRAY(`json_value`),
'$[*]' COLUMNS(
NESTED PATH '$**.*' COLUMNS(
`value` DECIMAL(10, 2) PATH '$.value',
`realized` VARCHAR(5) PATH '$.realized'
)
)
) `der`
WHERE
`der`.`value` IS NOT NULL AND
`der`.`realized` = 'true'
GROUP BY
`milestone`.`id`;
请参见db-fiddle。