如何在MySQL dB 中搜索一个JSON 以满足要求的条件?

How to search a JSON in MySQL dB to satisfy the required condition?

假设我有一个 MySQL dB 的数据列表如下:

+----+------------+-------------------------------------------+
| id | index_date | token_json                                |
+----+------------+-------------------------------------------+
|  0 | 20200902_0 | [{"tk": [1, 2], "amt": [20, 49]}]         |
|  1 | 20200902_1 | [{"tk": [4, 3], "amt": [10, 39]}          |
|  2 | 20200902_2 | [{"tk": [7, 4], "amt": [12, 29]}          |
|  3 | 20200902_3 | [{"tk": [8, 7, 6], "amt": [13, 19, 19]}   |
|  4 | 20200902_4 | [{"tk": [9, 6], "amt": [25, 59]           |
+----+------------+-------------------------------------------+

token_json字段实际上是存储了一个JSON字符串。现在,我想获取此数据的子集,条件为 "sub_token" > 5。 输出子集应如下所示:

+----+------------+-------------------------------------------+
| id | index_date | token_json                                |
+----+------------+-------------------------------------------+
|  2 | 20200902_2 | [{"tk": [7, 4], "amt": [12, 29]}          |
|  3 | 20200902_3 | [{"tk": [8, 7, 6], "amt": [13, 19, 19]}   |
|  4 | 20200902_4 | [{"tk": [9, 6], "amt": [25, 59]           |
+----+------------+-------------------------------------------+

我尝试了下面的命令但不起作用。

SELECT * from my_table
WHERE JSON_EXTRACT(token_json, '$.tk') > 5; 

谁能指导我如何获得这样的子集? 我的 MySQL 版本是 5.7.19-17-57-log

如果你的数据库版本是8+,那么你可以使用JSON_TABLE()函数作为

WITH t(arr, id, token_json) AS
(
 SELECT JSON_EXTRACT(token_json, '$[*].tk'), id, token_json FROM my_table t
)
SELECT id, token_json
  FROM t 
 WHERE EXISTS 
 ( SELECT 1
     FROM t AS t2
     JOIN JSON_TABLE( CAST( arr AS JSON ), "$[*]"
             COLUMNS(
                     val INT PATH "$"
             )
          ) js
    WHERE t2.token_json = t.token_json     
      AND val > 5 )

Update : 考虑到你的数据库版本是5.7,你可以使用如下方法:

SELECT id, token_json
  FROM my_table
 WHERE id IN
       (SELECT id
          FROM (SELECT JSON_EXTRACT(JSON_EXTRACT(token_json, '$[*].tk'),
                                    CONCAT('$[', i, ']')) AS val,
                       t.*
                  FROM my_table t
                  JOIN (SELECT @i := @i + 1 AS i
                         FROM information_schema.tables i
                         JOIN (SELECT @i := -1) AS iter
                        WHERE @i < (SELECT MAX(JSON_LENGTH(token_json))
                                      FROM my_table) - 1) AS t) AS tt
         WHERE val > 5)

Demo

更新 2:如果您将值转换为这种格式(如上一条评论所述);

+----+------------+---------------------------------------------+
| id | index_date | token_json                                  |
+----+------------+---------------------------------------------+
|  0 | 20200902_0 | {"tk": [1,2], "amt": [20,49]}               |
|  1 | 20200902_1 | {"tk": [4,3,2], "amt": [10,39,19]}          |
|  2 | 20200902_2 | {"tk": [7,4], "amt": [12,29]}               |
|  3 | 20200902_3 | {"tk": [8,7,6], "amt": [13,19,19]}          |
|  4 | 20200902_4 | {"tk": [9,6], "amt": [25,59]}               |
+----+------------+---------------------------------------------+

然后你可以使用(对于5.7):

SELECT id, token_json
  FROM my_table
 WHERE id IN
       (SELECT id
          FROM (SELECT JSON_EXTRACT(JSON_EXTRACT(token_json, '$.tk'),
                                    CONCAT('$[', i, ']')) AS elm,
                       t.*
                  FROM my_table t
                  JOIN (SELECT @i := @i + 1 AS i
                         FROM information_schema.tables i
                         JOIN (SELECT @i := -1) AS iter
                        WHERE @i < (SELECT MAX(JSON_LENGTH(token_json))
                                      FROM my_table) - 1) AS t) AS tt
         WHERE elm > 5)

你可以使用(对于 8.0 ):

WITH t(arr, id, token_json) AS
(
 SELECT JSON_EXTRACT(token_json, '$.tk') AS arr, id, token_json FROM my_table t
)
SELECT id, token_json
  FROM t 
 WHERE EXISTS 
 ( SELECT 1
     FROM t AS t2
     JOIN JSON_TABLE( CAST( arr AS JSON ), "$[*]"
             COLUMNS(
                     val INT PATH "$"
             )
          ) js
    WHERE t2.token_json = t.token_json     
      AND val > 5 ) 

Demo