【问题标题】:Query mysql json column array using AND NOT CONTAINS (mysql 5.7)使用 AND NOT CONTAINS (mysql 5.7) 查询 mysql json 列数组
【发布时间】:2021-01-04 12:31:12
【问题描述】:

我有一个包含对象数组的 json 列的表,如下所示:

create table test_json (json_id int not null primary key, json_data json not null) select 1 as json_id, '[{"category":"circle"},{"category":"square", "qualifier":"def"}]' as json_data union select 2 as json_id, '[{"category":"triangle", "qualifier":"xyz"},{"category":"square"}]' as json_data;
+---------+----------------------------------------------------------------------------------------+
| json_id | json_data                                                                              |
+--------------------------------------------------------------------------------------------------+
| 1       | [{"category":"circle"},   {"category":"square", "qualifier":"def"}]                    |
| 2       | [{"category":"triangle", "qualifier":"xyz"}, {"category":"square"}]                    |
+---------+----------------------------------------------------------------------------------------+

我希望能够查询此表以查找数组中包含 json 对象的任何行 (json_id's),其中“类别”值为“square”且没有“限定符”属性。

上面的示例表只是一个示例,我正在寻找一个可以处理 json 数组中数百行和数百个对象的查询。

【问题讨论】:

    标签: mysql mysql-5.7 mysql-json


    【解决方案1】:

    在 MySQL 8.0 中,您可以为此使用 JSON_TABLE():

    mysql> select json_id, j.* from test_json, json_table(json_data, '$[*]' columns (
        category varchar(20) path '$.category',
        qualifier varchar(10) path '$.qualifier')) as j 
      where j.category = 'square' and j.qualifier is null;
    +---------+----------+-----------+
    | json_id | category | qualifier |
    +---------+----------+-----------+
    |       2 | square   | NULL      |
    +---------+----------+-----------+
    

    目前还不清楚您为什么要为此使用 JSON。最好以正常方式存储数据,每个对象一行,将categoryqualifier 作为单独的列。

    针对普通列的查询编写起来要简单得多,并且您可以使用索引轻松优化查询:

    select * from mytable where category = 'square' and qualifier is null;
    

    我找到了另一个仅使用 MySQL 5.7 JSON 函数的解决方案:

    select json_id, json_data from test_json 
    where json_extract(json_data,
      concat(
        trim(trailing '.category' from 
          json_unquote(json_search(json_data, 'one', 'square'))
        ),
      '.qualifier')
    ) is null
    

    这假定值“square”作为"category" 字段的值出现。在您的简单示例中确实如此,但我不知道在您的真实数据中是否如此。

    结果:

    +---------+------------------------------------------------------------------------+
    | json_id | json_data                                                              |
    +---------+------------------------------------------------------------------------+
    |       2 | [{"category": "triangle", "qualifier": "xyz"}, {"category": "square"}] |
    +---------+------------------------------------------------------------------------+
    

    我仍然认为,只要您在 WHERE 子句的条件中引用 JSON 列,它就是 CodeSmell。我理解您的评论,这是一个简化的示例,但无论 JSON 结构如何,如果您需要执行搜索条件,如果您的数据存储在规范化表的常规列中,您的查询将更容易开发。

    【讨论】:

    • 哦,我的理解是 JSON_TABLE 仅在 mysql 8 中可用。我需要查询 mysql 5.7。
    • 正确,JSON_TABLE() 仅在 MySQL 8.0 中。我会将数据存储在普通列中。
    • 我的数据结构比我在这里包含的示例要复杂得多。如果真的这么简单,我同意,我不会使用 json。
    • 即使数据更复杂,我仍然会避免将 JSON 用于我想在 WHERE 子句的条件中引用的任何列。根据数据的复杂性,您可能需要不止一张额外的表格。
    • 原因是如果使用 JSON 数组,则无法使用索引优化查询。您必须进行表扫描,这很昂贵。 MySQL 8.0 中有一种新的索引类型用于索引 JSON 数组,但正如您所说,您仍在使用 5.7。
    【解决方案2】:

    您的要求不清楚。您的两条 SQL 记录都没有此类属性,但您的 JSON 对象具有。也许您尝试查找具有此类对象的任何记录。所以以下是你的答案:

    create table test_json (json_id int not null primary key, json_data json not null) select 1 as json_id, '[{"category":"circle", "qualifier":"abc"},{"category":"square", "qualifier":"def"}]' as json_data union select 2 as json_id, '[{"category":"triangle", "qualifier":"xyz"},{"category":"square"}]' as json_data;
    select * from test_json;
    select * from test_json where 'square' in (JSON_EXTRACT(json_data, '$[0].category'),JSON_EXTRACT(json_data, '$[1].category'))
    AND (JSON_EXTRACT(json_data, '$[0].qualifier') is NULL || JSON_EXTRACT(json_data, '$[1].qualifier') is NULL);
    

    Online Demo

    另见JSON Function Reference

    【讨论】:

    • 抱歉,我已将问题更新为更具体。
    • 您的查询将匹配 json 值为 [{"category":"circle"}, {"category":"square", "qualifier":"def"}] 的行,这是不应该的。
    猜你喜欢
    • 1970-01-01
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    • 2011-05-08
    • 2022-01-07
    • 2021-10-22
    • 1970-01-01
    相关资源
    最近更新 更多