英文:
Find out the sum of all the elements in json array in mysql with filtering
问题
-
是的,
amounts
数组和flag
数组中的元素顺序与details
中的元素顺序相同。因此,您可以根据这个顺序正确计算总和。 -
如果您的MariaDB版本不支持
json_table
,您目前的查询方法是一种有效的方式。但如果要在数据库层面更高效地进行求和,您可能需要考虑升级到支持json_table
的版本,这将使操作更简单和高效。否则,您可能需要继续在应用程序代码中进行求和处理,就像您目前所做的那样。
英文:
I am using mariadb version 10.2.43-MariaDB-1:10.2.43+maria~bionic
Table schema
The table has a columns id
attribute and details
array with the following two rows of data :
{
"id": 9,
"details": [
{
"amount": 100,
"flag": true,
"fieldA": "abcd"
},
{
"amount": 101,
"flag": false,
"fieldB": "bcde"
},
{
"amount": 103,
"flag": true,
"fieldA": "abcd"
}
]
},
{
"id": 10,
"details": [
{
"amount": 110,
"flag": false,
"fieldA": "abcd"
},
{
"amount": 102,
"flag": true,
"fieldB": "bcde"
}
]
}
I want to calculate the sum of amounts when the flag is true.
- For id = 9 amounts = [100, 103]
- For id = 10 amounts = [102]
- Total = 100 + 103 + 102 = 305
On searching online I found a few answers suggesting json_table
but we are using older version of mariadb which does not support json_table.
I have used this way to extract the amounts and flags and then finally handled the sum in code.
SELECT JSON_EXTRACT(features,'$. details[*].amount') as amounts,
JSON_EXTRACT(features,'$.details[*].flag') as flag
FROM table
WHERE JSON_EXTRACT(features,'$.details[*].flag') != 'NULL';
Output
-------------------------------------------------------------+---------------------------------------------------------------------+
| [500000, 1000000] | [false, false] |
| [1100000] | [false] |
| [1000000] | [false] |
| [500000, 1000000] | [false, false] |
| [100000] | [false] |
| [5000000] | [false] | |
| [50000] | [false] |
| [500000] | [false] |
| [500000] | [false] |
| [10000] | [true] |
| [49998] | [true] |
| [600000, 399980] | [false, true]
Questions:
- I want to know if the order of elements in amounts array and flag array will be the same as that in details. (otherwise the sum I am calculating will be wrong).
- Is there a more efficient way to calculate the sum without using code?
答案1
得分: 1
-
我想知道金额数组和标志数组的元素顺序是否与详情中的顺序相同(否则我计算的总和将是错误的)。
-
是否有一种更有效的方法来计算总和,而不使用代码?
MariaDB不支持json_table
,它可以将JSON数组展开为行。但是我们可以借助数字表和其他MariaDB JSON函数来模拟它。
有许多不同的方法可以创建数字表,可以是查询内联的方式,也可以永久存储在一个表中。这里我只是使用了一个固定的数字列表:
从mytable t
中选择json_value(t.details, concat('$[', n.i, '].amount'))
的总金额
从mytable t
内部加入(选择0 as i联合全部选择1联合全部选择2)n
其中n.i < json_length(t.details)
并且json_value(t.details, concat('$[', n.i, '].flag')) = True
联接n
生成JSON数组中每个项目的一行;鉴于元素的索引,我们可以生成其金额和标志的适当JSON路径(这就是concat()
的作用),并使用json_value()
访问这些值。
我手头没有MariaDB 10.2数据库来测试,但这里是**一个MariaDB 10.3示例**。请注意,数据库正确识别了flag
属性中的布尔值,这简化了where
子句。
英文:
> 1) I want to know if the order of elements in amounts array and flag array will be the same as that in details. (otherwise the sum I am calculating will be wrong).
The documentation says:
> Extracts data from a JSON document. [...]. Returns all matched values; either as a single matched value, or, if the arguments could return multiple values, a result autowrapped as an array in the matching order.
So yes, both calls to json_extract
will give you an ordered slice of the json array. But note that, as far as your query goes, you are still left with the task of unesting each slice (the two arrays that you are getting)... which is the core of the task, and brings us to your second question.
> 2. Is there a more efficient way to calculate the sum without using code?
MariaDB does not support json_table
, which can expand a json array to rows. But we can emulate it with the help of a table of numbers and of other MariaDB json functions.
There are many different ways that you can create a table of numbers, either inline in the query or permanently stored in a table. Here I am just using a fixed list of a few numbers :
select sum( json_value( t.details, concat('$[', n.i, '].amount') ) ) total_amount
from mytable t
inner join (select 0 as i union all select 1 union all select 2) n
on n.i < json_length(t.details)
where json_value( t.details, concat('$[', n.i, '].flag') )
The join on n
generate one row for each item in the JSON array; given the index of the element, we can generate the proper json path to its amount and flag (that's what the concat()
s do), and access the values with json_value()
.
I don't have a MariaDB 10.2 database at hand to test, but here is a MariaDB 10.3 fiddle. Note the database properly recognizes the boolean value in the flag
attribute, which simplifies the where
clause.
答案2
得分: 1
以下是您要翻译的内容:
一种选项是在通过 Recursive CTE
循环时使用 JSON_EXTRACT()
函数,该函数在 10.2.2 + 版本中受支持,如下查询所示:
WITH RECURSIVE cte AS
(
SELECT 0 i
UNION ALL
SELECT i + 1 i
FROM cte
WHERE i + 1 <= ( SELECT MAX(JSON_LENGTH(features, '$.details')) FROM t )
)
SELECT SUM(CASE
WHEN JSON_EXTRACT(features, CONCAT('$.details[',i,'].flag')) = 'true' THEN
CAST(JSON_EXTRACT(features, CONCAT('$.details[',i,'].amount')) AS DOUBLE)
END) AS sum_amount
FROM cte,
t
<kbd>[演示](https://dbfiddle.uk/XP1rxC7P)</kbd>
英文:
One option is to use JSON_EXTRACT()
function while looping through by Recursive CTE
which's supported for 10.2.2 + as in the following query
WITH RECURSIVE cte AS
(
SELECT 0 i
UNION ALL
SELECT i + 1 i
FROM cte
WHERE i + 1 <= ( SELECT MAX(JSON_LENGTH(features, '$.details')) FROM t )
)
SELECT SUM(CASE
WHEN JSON_EXTRACT(features, CONCAT('$.details[',i,'].flag')) = 'true' THEN
CAST(JSON_EXTRACT(features, CONCAT('$.details[',i,'].amount')) AS DOUBLE)
END) AS sum_amount
FROM cte,
t
<kbd>Demo</kbd>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论