如何计算MySQL JSON数组中每个值的个数?
How to calculate count of each value in MySQL JSON array?
我有一个 MySQL
table 具有以下定义:
mysql> desc person;
+--------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | text | YES | | NULL | |
| fruits | json | YES | | NULL | |
+--------+---------+------+-----+---------+-------+
table有一些示例数据如下:
mysql> select * from person;
+----+------+----------------------------------+
| id | name | fruits |
+----+------+----------------------------------+
| 1 | Tom | ["apple", "orange"] |
| 2 | John | ["apple", "mango"] |
| 3 | Tony | ["apple", "mango", "strawberry"] |
+----+------+----------------------------------+
如何计算每个水果出现的总次数?例如:
+------------+-------+
| fruit | count |
+------------+-------+
| apple | 3 |
| orange | 1 |
| mango | 2 |
| strawberry | 1 |
+------------+-------+
一些研究表明可以使用 JSON_LENGTH
函数,但我找不到与我的场景类似的示例。
如果不先创建一个每个水果一行的 table,就无法做到这一点。
CREATE TABLE allfruits (fruit VARCHAR(10) PRIMARY KEY);
INSERT INTO allfruits VALUES ('apple'), ('orange'), ('mango'), ('strawberry');
没有从 JSON.
生成这个的好方法
获得 table 后,您可以将其加入 JSON,然后使用 GROUP BY 计算出现次数。
SELECT fruit, COUNT(*) AS count
FROM allfruits
JOIN person ON JSON_SEARCH(person.fruits, 'one', fruit) IS NOT NULL
GROUP BY fruit;
输出:
+------------+-------+
| fruit | count |
+------------+-------+
| apple | 3 |
| mango | 2 |
| orange | 1 |
| strawberry | 1 |
+------------+-------+
请注意,它会对人 table 进行 table 扫描以找到每个水果。这是相当低效的,随着你的人 table 变大,这将成为一个性能问题。
如果要针对此类查询进行优化,则不应使用 JSON 来存储水果数组。您应该以规范化的方式存储数据,表示人和水果与另一个 table 之间的多对多关系。
这与我对Is storing a delimited list in a database column really that bad?
的回答有关
您可以使用 JSON_EXTRACT()
函数提取数组所有三个分量的每个值("apple"、"mango"、"strawberry" 和 "orange") ,然后应用 UNION ALL
组合所有此类查询:
SELECT comp, count(*)
FROM
(
SELECT JSON_EXTRACT(fruit, '$[0]') as comp FROM person UNION ALL
SELECT JSON_EXTRACT(fruit, '$[1]') as comp FROM person UNION ALL
SELECT JSON_EXTRACT(fruit, '$[2]') as comp FROM person
) q
WHERE comp is not null
GROUP BY comp
确实如果你的DB版本是8,那么你也可以使用JSON_TABLE()
函数:
SELECT j.fruit, count(*)
FROM person p
JOIN JSON_TABLE(
p.fruits,
'$[*]' columns (fruit varchar(50) path '$')
) j
GROUP BY j.fruit;
我认为最简单的解决方案是使用 JSON_TABLE
函数。
您需要的查询是
select ft.fruit, count(ft.fruit) from person,
json_table(
fruits,
'$[*]' columns(
fruit varchar(128) path '$'
)
) as ft
group by ft.fruit
;
您可以在这个 dbfiddle 中找到工作示例
Fruit demo
我有一个 MySQL
table 具有以下定义:
mysql> desc person;
+--------+---------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+--------+---------+------+-----+---------+-------+
| id | int(11) | NO | PRI | NULL | |
| name | text | YES | | NULL | |
| fruits | json | YES | | NULL | |
+--------+---------+------+-----+---------+-------+
table有一些示例数据如下:
mysql> select * from person;
+----+------+----------------------------------+
| id | name | fruits |
+----+------+----------------------------------+
| 1 | Tom | ["apple", "orange"] |
| 2 | John | ["apple", "mango"] |
| 3 | Tony | ["apple", "mango", "strawberry"] |
+----+------+----------------------------------+
如何计算每个水果出现的总次数?例如:
+------------+-------+
| fruit | count |
+------------+-------+
| apple | 3 |
| orange | 1 |
| mango | 2 |
| strawberry | 1 |
+------------+-------+
一些研究表明可以使用 JSON_LENGTH
函数,但我找不到与我的场景类似的示例。
如果不先创建一个每个水果一行的 table,就无法做到这一点。
CREATE TABLE allfruits (fruit VARCHAR(10) PRIMARY KEY);
INSERT INTO allfruits VALUES ('apple'), ('orange'), ('mango'), ('strawberry');
没有从 JSON.
生成这个的好方法获得 table 后,您可以将其加入 JSON,然后使用 GROUP BY 计算出现次数。
SELECT fruit, COUNT(*) AS count
FROM allfruits
JOIN person ON JSON_SEARCH(person.fruits, 'one', fruit) IS NOT NULL
GROUP BY fruit;
输出:
+------------+-------+
| fruit | count |
+------------+-------+
| apple | 3 |
| mango | 2 |
| orange | 1 |
| strawberry | 1 |
+------------+-------+
请注意,它会对人 table 进行 table 扫描以找到每个水果。这是相当低效的,随着你的人 table 变大,这将成为一个性能问题。
如果要针对此类查询进行优化,则不应使用 JSON 来存储水果数组。您应该以规范化的方式存储数据,表示人和水果与另一个 table 之间的多对多关系。
这与我对Is storing a delimited list in a database column really that bad?
的回答有关您可以使用 JSON_EXTRACT()
函数提取数组所有三个分量的每个值("apple"、"mango"、"strawberry" 和 "orange") ,然后应用 UNION ALL
组合所有此类查询:
SELECT comp, count(*)
FROM
(
SELECT JSON_EXTRACT(fruit, '$[0]') as comp FROM person UNION ALL
SELECT JSON_EXTRACT(fruit, '$[1]') as comp FROM person UNION ALL
SELECT JSON_EXTRACT(fruit, '$[2]') as comp FROM person
) q
WHERE comp is not null
GROUP BY comp
确实如果你的DB版本是8,那么你也可以使用JSON_TABLE()
函数:
SELECT j.fruit, count(*)
FROM person p
JOIN JSON_TABLE(
p.fruits,
'$[*]' columns (fruit varchar(50) path '$')
) j
GROUP BY j.fruit;
我认为最简单的解决方案是使用 JSON_TABLE
函数。
您需要的查询是
select ft.fruit, count(ft.fruit) from person,
json_table(
fruits,
'$[*]' columns(
fruit varchar(128) path '$'
)
) as ft
group by ft.fruit
;
您可以在这个 dbfiddle 中找到工作示例 Fruit demo