mysql - 在 MariaDB/MySQL 中的多级 JSON 中查询特定值

标签 mysql sql json mariadb

我正在使用一个 MariaDB 表,该表的 JSON 值存储如下:

{"nextValue":4,"1":{"text":"Item1","textDisplay":"","value":1,"isActive":0},"2":{"text":"Item2","textDisplay":"","value":2,"isActive":1},"3":{"text":"Item3","textDisplay":"","value":3,"isActive":1}}

我想做的是构建一个查询,我可以在其中有一个列作为项目,即“Item2”,并且在下一列中具有来自该 JSON 的键“值”的值。因此,如果“Item2”返回,在它旁边的列中,它会显示“2”。

我已经尝试过许多适用于 MariaDB 的 JSON 选项,但我就是不知道该怎么做。

最佳答案

我用 MySQL 8.0 测试了以下内容。根据其文档,它使用的函数似乎存在于 MariaDB 中,但我没有要测试的 MariaDB 实例。

SELECT * FROM mytable;
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| data                                                                                                                                                                                                                               |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| {"1": {"text": "Item1", "value": 1, "isActive": 0, "textDisplay": ""}, "2": {"text": "Item2", "value": 2, "isActive": 1, "textDisplay": ""}, "3": {"text": "Item3", "value": 3, "isActive": 1, "textDisplay": ""}, "nextValue": 4} |
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

SELECT JSON_UNQUOTE(JSON_EXTRACT(JSON_EXTRACT(data, REPLACE(JSON_UNQUOTE(JSON_SEARCH(data, 'one', 'Item2')), '.text', '')), '$.value')) AS value FROM mytable;
+-------+
| value |
+-------+
| 2     |
+-------+

这非常脆弱,依赖于对 JSON 路径进行字符串替换,然后在进一步的 JSON 函数中使用这些路径。开发和维护如此复杂的 SQL 语句将花费您的雇主大量工程师工时。

另一种方法是升级到 MySQL 8.0 并使用 JSON_TABLE()函数将您的 JSON 文档映射到派生表中,然后您可以在 WHERE 子句中使用条件。

SELECT j.* FROM mytable2, 
JSON_TABLE(mytable2.data, '$[*]' 
  COLUMNS (
    rowid FOR ORDINALITY,
    `text` VARCHAR(20) PATH '$.text',
    textDisplay TEXT PATH '$.textDisplay',
    value INT PATH '$.value',
    isActive BOOL PATH '$.isActive'
  )
) AS j

+-------+-------+-------------+-------+----------+
| rowid | text  | textDisplay | value | isActive |
+-------+-------+-------------+-------+----------+
|     1 | Item1 |             |     1 |        0 |
|     2 | Item2 |             |     2 |        1 |
|     3 | Item3 |             |     3 |        1 |
+-------+-------+-------------+-------+----------+

但这不适用于您拥有的 JSON 数据,因为该函数仅在您的 JSON 是数组时才有效,而您的数据被格式化为 JSON 对象。仅当我将您的 JSON 数据格式更改为数组时,我才使上面的示例有效:

select * from mytable2;
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| data                                                                                                                                                                                                |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| [{"text": "Item1", "value": 1, "isActive": 0, "textDisplay": ""}, {"text": "Item2", "value": 2, "isActive": 1, "textDisplay": ""}, {"text": "Item3", "value": 3, "isActive": 1, "textDisplay": ""}] |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+

您的开发人员设计的 JSON 格式旨在使他们能够轻松插入数据,但这完全是对 JSON 的无偿使用,它使对数据的查询变得不必要的复杂。这是 Inner-Platform Effect 的一个例子:

The inner-platform effect is the tendency of software architects to create a system so customizable as to become a replica, and often a poor replica, of the software development platform they are using. This is generally inefficient and such systems are often considered to be examples of an anti-pattern.

正如我在上面评论的那样,我会把它设计成一个普通的 SQL 表:

CREATE TABLE Items (
  id INT AUTO_INCREMENT PRIMARY KEY,
  `text` VARCHAR(20), 
  textDisplay TEXT, 
  value INT, 
  isActive BOOL
);

用每列中的值填充它:

INSERT INTO Items 
VALUES (1, 'Item1', '', 1, 0),
       (2, 'Item2', '', 2, 1),
       (3, 'Item3', '', 3, 1);

然后就可以很简单的查询了:

SELECT value FROM Items WHERE `text` = 'Item2';
+-------+
| value |
+-------+
|     2 |
+-------+

您的雇主应该喜欢以正常方式存储数据的简单性,因为在查询数据时他们会节省大量时间和金钱。

关于mysql - 在 MariaDB/MySQL 中的多级 JSON 中查询特定值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55345503/

相关文章:

mysql - 使用 MySQL 创建简单修订系统的最佳方法是什么?

PHP/MYSQL sql选择

php - MySql Select 查询中的正则表达式替换

mysql - 无法远程将 CSV 加载到 MySQL 中

javascript - Aurelia PHP Post 请求为空 $_POST

php - @(或 "at sign")提前结束我的 MySQL 查询,导致错误

php - 如何将父表当前主键的值插入到子表中

php - MySQL:如何检查用户(自己)是否有创建临时表的权限

PHP 查询在表中搜索 Json 值

android - Android 中无法单独获取 JSON 值