MYSQL:如何查询JSON数组包含特定标签的位置

时间:2019-03-10 14:35:20

标签: mysql json

MySQL 5.7.24

让我们说我有3行:

ID (PK) | Name (VARCHAR) | Data (JSON)
--------+----------------+-------------------------------------
 1      | Admad          | [{"label":"Color", "value":"Red"}, {"label":"Age", "value":40}]
 2      | Saleem         | [{"label":"Color", "value":"Green"}, {"label":"Age", "value":37}, {"label":"Hoby", "value":"Chess"}]
 3      | Daniel         | [{"label":"Food", "value":"Grape"}, {"label":"Age", "value":47}, {"label":"State", "value":"Sel"}]

规则1:“ JSON”列是动态的。意味着并非每个人都有相同的结构

规则2:假设我无法修改数据结构

我的问题是,可以查询以便获取年龄> = 40的记录的ID?在这种情况下为1和3。

附加信息(在指向重复项之后):如果查看我的数据,则父容器是数组。如果我将数据存储为

{"Age":"40", "Color":"Red"} 

然后我可以简单地使用

Data->>'$.Age' >= 40

我当前的想法是使用存储过程来循环数组,但我希望不必走那条路线。第二种选择是使用正则表达式(我也希望不要)。如果您认为“ JSON搜索”是解决方案,请给我指出哪一个(或对此我的菜鸟的一些示例)。该文档太笼统,无法满足我的特定需求。

1 个答案:

答案 0 :(得分:3)

这是一个演示:

mysql> create table letsayi (id int primary key, name varchar(255), data json);

mysql> > insert into letsayi values
-> (1, 'Admad', '[{"label":"Color", "value":"Red"}, {"label":"Age", "value":"40"}]'),
-> (2, 'Saleem', '[{"label":"Color", "value":"Green"}, {"label":"Age", "value":"37"}, {"label":"Hoby", "value":"Chess"}]');

mysql>  select id, name from letsayi 
        where json_contains(data, '{"label":"Age","value":"40"}');
+----+-------+
| id | name  |
+----+-------+
|  1 | Admad |
+----+-------+

我不得不说这是存储数据的最不高效的方法。即使您在生成的列上使用索引,也无法使用索引来搜索数据。您甚至没有将整数“ 40”存储为整数,而是将数字存储为字符串,这使它们占用更多空间。

不需要时在MySQL中使用JSON是一个好主意。


  

是否仍然可以查询年龄> = 40?

不使用JSON_CONTAINS()。该函数不像WHERE子句中的不等式条件。它只匹配子文档的完全相等。

要实现不平等,您必须升级到MySQL 8.0并使用JSON_TABLE()。我最近回答了另一个问题:MySQL nested JSON column search and extract sub JSON

换句话说,您必须将JSON转换为一种格式,就像将其存储在传统的行和列中一样。但是,每次查询数据时,您都必须这样做。

如果您需要在WHERE子句中使用条件,最好不要使用JSON。这只会使您的查询过于复杂。听有关编程的旧建议:

  

“调试是一开始编写代码的两倍。因此,如果您尽可能聪明地编写代码,就定义而言,您就不够聪明,无法对其进行调试。”   —布赖恩·克尼根(Brian Kernighan)


  

人们如何处理动态添加的表单字段

您可以为动态表单字段创建键/值表:

CREATE TABLE keyvalue (
  user_id INT NOT NULL,
  label VARCHAR(64) NOT NULL,
  value VARCHAR(255) NOT NULL,
  PRIMARY KEY (user_id, label),
  INDEX (label)
);

然后,您可以为每个用户的动态表单条目添加键/值对:

INSERT INTO keyvalue (user_id, label, value)
VALUES (123, 'Color', 'Red'),
       (123, 'Age', '40');

与实列相比,这在存储方面仍然效率低下,因为每次输入用户数据时都会存储标签名称,并且仍将整数存储为字符串。但是,如果确实允许用户存储他们自己选择的任何标签,则不能创建这些真实的列。

使用键/值表,年龄> 40岁的查询更简单:

SELECT user_id FROM key_value
WHERE label = 'Age' AND value >= 40