MySQL通过数组中的键搜索json值

Posted

技术标签:

【中文标题】MySQL通过数组中的键搜索json值【英文标题】:MySQL search json value by key in array 【发布时间】:2019-09-12 13:21:40 【问题描述】:

我有一个 JSON 对象数组,并希望返回一个特定节点。为了简化我的问题,假设数组可能如下所示:

[
    "Race": "Orc", "strength": 14,
    "Race": "Knight", "strength": 7,
    ...
]

例如,我想知道骑士的力量。 函数JSON_SEARCH,返回路径'$[1].Race' 和path operator 我可以得到力量。有没有办法将这两者结合起来,所以我可以做如下的事情?

SELECT someFunc(myCol,'$[*].Race','Orc','$.strength') AS strength
FROM myTable

我使用的是 mysql 8.0.15。

【问题讨论】:

为什么不使用普通的列和关系来代替 json,可能会更快的查找并且你不必为逻辑和魔法而烦恼。 @DanFromGermany 感谢您的编辑。我不使用普通的列和关系,因为实际数据是我不知道其结构的东西。实际数据更像是工作用品的 json 数组,我想获取电话号码。但是 json 数据可能包含普通的东西,比如手机和笔记本电脑,但也可能包含奇怪的东西,比如自行车或 nerf 枪。每种类型只能包含一次,但整个过程都在使用 json 数组,此时没有固定结构的重写是没有意义的:( 【参考方案1】:

本质上,您的意思是将selection and projection 应用于 JSON 文档的数组元素和对象字段。您需要执行 WHERE 子句之类的操作来选择数组中的“行”,然后执行诸如选择其中一个字段(而不是您在选择条件中使用的字段)之类的操作。

这些是在 SQL 中使用 WHERE 子句和列的 SELECT-list 完成的,但对 JSON 执行相同操作并不是您可以使用 JSON_SEARCH() 和 JSON_CONTAINS() 之类的函数轻松完成的。

MySQL 8.0 提供的解决方案是 JSON_TABLE() 函数,用于将 JSON 文档转换为虚拟派生表——就好像您已经定义了传统的行和列一样。如果 JSON 采用您描述的格式(对象数组),它就可以工作。

这是我通过将示例数据插入到表格中所做的演示:

create table mytable ( mycol json );

insert into mytable set mycol = '["Race": "Orc", "strength": 14, "Race": "Knight", "strength": 7]';

SELECT j.* FROM mytable, JSON_TABLE(mycol, 
  '$[*]' COLUMNS (
    race VARCHAR(10) PATH '$.Race', 
    strength INT PATH '$.strength'
  )
) AS j;
+--------+----------+
| race   | strength |
+--------+----------+
| Orc    |       14 |
| Knight |        7 |
+--------+----------+

现在您可以执行通常使用 SELECT 查询执行的操作,例如选择和投影:

SELECT j.strength FROM mytable, JSON_TABLE(mycol, '$[*]' 
  COLUMNS (
    race VARCHAR(10) PATH '$.Race', 
    strength INT PATH '$.strength'
  )
) AS j 
WHERE j.race = 'Orc'
+----------+
| strength |
+----------+
|       14 |
+----------+

这有几个问题:

    您需要每次查询 JSON 数据,或者创建一个 VIEW 来执行此操作。

    您说您不知道属性字段,但要编写 JSON_TABLE() 查询,您必须在查询中指定要搜索和投影的属性。您不能将其用于完全未定义的数据。

我已经回答了很多关于在 MySQL 中使用 JSON 的类似问题。我观察到,当您想要执行此类操作时,将 JSON 文档视为表格,以便您可以将 WHERE 子句中的条件应用于 JSON 数据中的字段,那么您的所有查询都会变得更加困难。然后你开始觉得你最好花几分钟来定义你的属性,这样你就可以编写更简单的查询。

【讨论】:

谢谢。我希望除了 JSON_TABLE() 之外还有另一种方法,但显然没有,除了彻底改变业务逻辑。【参考方案2】:

在 SQL 5.7 中有解决此问题的方法。我将逐步编写解决方案。目标是找到骑士的力量。

我将使用与上一篇文章相同的示例表:

create table mytable ( mycol json );

insert into mytable set mycol = '["Race": "Orc", "strength": 14, "Race": "Knight", "strength": 7]';

首先,获取一个仅包含种族的数组。

select json_extract(mycol, '$[*].Race') from mytable;
+----------------------------------+
| json_extract(mycol, '$[*].Race') |
+----------------------------------+
| ["Orc", "Knight"]                |
+----------------------------------+

然后,在这个数组中搜索 Knight(并取消引用)。

select json_unquote(json_search(json_extract(mycol, '$[*].Race'), 'one', 'Knight')) from mytable;
+------------------------------------------------------------------------------+
| json_unquote(json_search(json_extract(mycol, '$[*].Race'), 'one', 'Knight')) |
+------------------------------------------------------------------------------+
| $[1]                                                                         |
+------------------------------------------------------------------------------+

找到索引后,从数组中获取这个元素。

select json_extract(mycol, json_unquote(json_search(json_extract(mycol, '$[*].Race'), 'one', 'Knight'))) from mytable;
+---------------------------------------------------------------------------------------------------+
| json_extract(mycol, json_unquote(json_search(json_extract(mycol, '$[*].Race'), 'one', 'Knight'))) |
+---------------------------------------------------------------------------------------------------+
| "Race": "Knight", "strength": 7                                                                 |
+---------------------------------------------------------------------------------------------------+

然后得到这个元素的强度。

select json_extract(json_extract(mycol, json_unquote(json_search(json_extract(mycol, '$[*].Race'), 'one', 'Knight'))), '$.strength') as strength from mytable;
+----------+
| strength |
+----------+
| 7        |
+----------+

您可以在其他字段上重复此操作以创建其他列。

【讨论】:

【参考方案3】:

查看 JSON_CONTAINS (https://dev.mysql.com/doc/refman/8.0/en/json-search-functions.html#function_json-contains) 并在您的 WHERE 子句中使用它来识别符合您条件的记录。

【讨论】:

请查看如何格式化您的答案以提高可读性。

以上是关于MySQL通过数组中的键搜索json值的主要内容,如果未能解决你的问题,请参考以下文章

通过在键和值中搜索部分匹配来过滤数组元素

如何在JSON.NET中读取json对象值中的long值数组

如何比较字典值中的多个数组,并将每个数组元素的字典键映射到新数组/列表中

如何使用 AND 查询 MYSQL 中的 JSON 数组

在颤动中 - 我如何最好地处理和分配预先确定的键给 json 中的嵌套列表/数组

如何在mysql表中搜索json数组字段中的字段?