用于确定 JSON 值是不是包含指定属性的 SQL 查询

Posted

技术标签:

【中文标题】用于确定 JSON 值是不是包含指定属性的 SQL 查询【英文标题】:SQL query to determine if a JSON value contains a specified attribute用于确定 JSON 值是否包含指定属性的 SQL 查询 【发布时间】:2017-02-05 12:22:53 【问题描述】:

我有一个表,其中有一列用于存储每行的 JSON 值。目前,这些还没有标准化。我想最终将这些 JSON 值中的每一个在属性的数量和标题上标准化。是否可以使用查询来确定每个 JSON 值是否包含指定的属性?

例如,下面是一些 JSON 值的样子:

"name":"Item 1","cost":"4.99"
"name":"Item 2"
"name":"Item 3","cost":""
"name":"Item 4"

我该怎么做:

确定哪些行具有“成本”属性(项目 1 和 3) 确定哪些行没有“成本”属性(项目 2 和 4) 确定哪些行为“成本”属性(第 1 项)设置了值

谢谢!这是我第一次询问(至少最近)所以非常感谢任何帮助!

【问题讨论】:

解析字段的字符串值,寻找cost属性。 【参考方案1】:

mysql 不解析 JSON 数组。它将它们视为字符串。所以你必须使用LIKE

【讨论】:

MySQL 5.7 内置 JSON 函数。 你应该展示LIKE模式来实现他的条件。【参考方案2】:

我假设您使用的是 MySQL 5.7,它添加了 JSON 数据类型。使用JSON_EXTRACT(colname, '$.cost') 访问cost 属性。它将是NULL,如果没有这样的属性。

    WHERE JSON_EXTRACT(colname, '$.cost') IS NOT NULL WHERE JSON_EXTRACT(colname, '$.cost') IS NULL WHERE JSON_EXTRACT(colname, '$.cost') != ''

如果 JSON 中的值为null,它也将是NULL;如果需要区分这种情况,请看Can't detect null value from JSON_EXTRACT

【讨论】:

令人遗憾的是,我无法区分属性不存在与属性存在,但没有价值。不过,这非常接近,并且会对我有很大帮助。谢谢! 您的 JSON 数据中是否都有 "cost": null 一些行有一个“成本”属性,但不是全部。我的目标是尝试快速整理出没有它的行,这样我就可以添加一个,然后使用 JSON 修改函数来更新那部分,而不是更新整个 JSON 字符串。 应该可以。您唯一无法区分的是"cost": null 中的无成本属性。 "cost": "" 仍然可以区分。 你的回答其实是准确的。 MySQL 确实将 SQL NULL 与 JSON 的 null 区分开来。您可以删除最后一条语句。有关详细信息,请参阅此答案:***.com/a/41172432/1128918【参考方案3】:

实际上,您可以通过将JSON_EXTRACT 结果与自身进行比较来做到这一点:

WHERE JSON_EXTRACT(colname, '$."cost"') = JSON_EXTRACT(colname, '$."cost"')

如果您的 JSON 列中没有相应的键,这将以某种方式为“假”/null。

通过这种方式,您可以找到所有具有您要搜索的键的条目。如果您想要所有没有密钥的条目,您就不能使用 NOT 运算符。你必须这样做:

SELECT * FROM tablename WHERE id NOT IN (SELECT id FROM tablename WHERE WHERE JSON_EXTRACT(colname, '$."cost"') = JSON_EXTRACT(colname, '$."cost"'))

我知道它看起来像伏都教,但它似乎有效。

【讨论】:

【参考方案4】:

如果只需要检查json键是否存在,可以使用JSON_CONTAINS_PATH。我希望它比 JSON_EXTRACT 更快。

mySQL 8.0 docs

例子:

我在数据库中有一个权限列。结构如下:


    "users": 
        "user1" : "rw",
        "user2" : "r"
    ,
    "groups": 
        "root": "rw",
        "anotherGroup" : "r"
    

如果我想获取所有具有根组的项目(关于实际权限),我使用这个:

SELECT * FROM `filesystem_folders` where JSON_CONTAINS_PATH(permissions, 'one', '$.groups.root');

我在上面的 select 之间做了一个非常简单的时间比较,耗时 12.90s(10000 次读取)。与使用 JSON_EXTRACT

的以下选择相比
 SELECT * FROM `filesystem_folders` where JSON_EXTRACT(permissions, '$.groups.root') IS NOT NULL;

耗时 15.13 秒。所以,差别很小。

【讨论】:

【参考方案5】:

如果您使用的是没有 JSON 函数的 MySQL(5.7 之前),或者想要检查列表中的任何标签,或者不可预测的嵌套 JSON。

这是一个如何使用LIKE 的示例:

SELECT case when colname like '%cost%' then 1 else 0 end as has_cost,
       case when colname like '%cost":""%' then 1 else 0 end as has_cost_with_no_value
FROM tablename

【讨论】:

MySQL 支持 JSON 查询,这对你需要做的事情来说太过分了。查看其他答案。

以上是关于用于确定 JSON 值是不是包含指定属性的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

json序列化后的是字符串,不是二进制。是字符串!!!确定不是二进制!!!

如何将具有十进制值的数字转换为PL / SQL中的浮点数?

指定分配索引值时,JavaScriptSerializer 不使用枚举 [重复]

SQL Server 如何确定序列中的下一个值?

第六章 SQL聚合函数 JSON_ARRAYAGG

Mysql 返回JSON值属性的函数