I am using mariadb version 10.2.43-MariaDB-1:10.2.43+maria~bionic
Table schema
The table has a column features
of type JSON with 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?
2
Answers
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 :
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 theconcat()
s do), and access the values withjson_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 thewhere
clause.One option is to use
JSON_EXTRACT()
function while looping through byRecursive CTE
which’s supported for 10.2.2 + as in the following queryDemo