MySQL按数组中的键搜索JSON值

时间:2019-04-23 11:05:23

标签: mysql json mysql-8.0 mysql-json

我有一个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。

3 个答案:

答案 0 :(得分:2)

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

这些是使用WHERE子句和列的SELECT-list在SQL中完成的,但使用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 |
+----------+

这有两个问题:

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

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

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

答案 1 :(得分: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        |
+----------+

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

答案 2 :(得分:-1)

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