MySQL 在数组中按键搜索 json 值

MySQL search json value by key in array

我有一个 JSON 对象数组,想要返回一个特定的节点。为了简化我的问题,假设数组看起来像这样:

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

我想知道骑士的实力。 函数JSON_SEARCH, returns the path '$[1].Race' and with the path operator我能得到力量。有没有办法将这两者结合起来,以便我可以执行以下操作?

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

我正在使用 MySQL 8.0.15.

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

您实际上是想将 selection and projection 应用于 JSON 文档的数组元素和对象字段。您需要对数组中的 select a "row" 执行 WHERE 子句之类的操作,然后执行诸如选择其中一个字段(不是您在 selection 标准中使用的字段)之类的操作).

这些是在 SQL 中使用 WHERE 子句和 SELECT 列列表完成的,但是用 JSON 做同样的事情不是你可以用函数轻松完成的像 JSON_SEARCH() 和 JSON_CONTAINS().

MySQL 8.0 提供的解决方案是 JSON_TABLE() 函数,可将 JSON 文档转换为虚拟派生 table — 就好像您定义了常规的行和列一样.如果 JSON 是您描述的格式,即对象数组,它会起作用。

这是我通过将您的示例数据插入到 table:

中所做的演示
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 查询执行的操作,例如 selection 和投影:

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 |
+----------+

这有几个问题:

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

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

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

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

我将使用与之前相同的示例 table post:

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        |
+----------+

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