【问题标题】:compare values with JSON_EXTRACT将值与 JSON_EXTRACT 进行比较
【发布时间】:2021-04-24 08:49:39
【问题描述】:

当我尝试将值与 JSON_EXTRACT 进行比较时遇到了一个奇怪的问题。

这是我在数据库中的 opening_hours 专栏的摘录:

{"1": {"end": {"max_hour": "1290", "min_hour": "840"}, "begin": {"max_hour": "720", "min_hour": "420"}}, 
 "2": {"end": {"max_hour": "1290", "min_hour": "840"}, "begin": {"max_hour": "720", "min_hour": "420"}}, 
 "3": {"end": {"max_hour": "1290", "min_hour": "840"}, "begin": {"max_hour": "720", "min_hour": "420"}}, 
 "4": {"end": {"max_hour": "1290", "min_hour": "840"}, "begin": {"max_hour": "720", "min_hour": "420"}}, 
 "5": {"end": {"max_hour": "1290", "min_hour": "840"}, "begin": {"max_hour": "720", "min_hour": "420"}}}

例如,当我搜索“720”是否介于一天中每个部分(开始和结束)的 min_hour 和 max_hour 之间时,我得到了结果:

SELECT *
FROM `service_provider`
WHERE ((JSON_EXTRACT(`opening_hours`, '$."3"."begin"."min_hour"') <= '720' 
        AND '720' <= JSON_EXTRACT(`opening_hours`, '$."3"."begin"."max_hour"')) 
      OR (JSON_EXTRACT(`opening_hours`, '$."3"."end"."min_hour"') <= '720' 
          AND '720' <= JSON_EXTRACT(`opening_hours`, '$."3"."end"."max_hour"')));

====> 得到了一些结果!

但是当我用“1200”做同样的事情时,没有找到结果:

SELECT *
FROM `service_provider`
WHERE ((JSON_EXTRACT(`opening_hours`, '$."3"."begin"."min_hour"') <= '1200' 
         AND '1200' <= JSON_EXTRACT(`opening_hours`, '$."3"."begin"."max_hour"')) 
      OR (JSON_EXTRACT(`opening_hours`, '$."3"."end"."min_hour"') <= '1200' 
           AND '1200' <= JSON_EXTRACT(`opening_hours`, '$."3"."end"."max_hour"')));

-----> 没有结果。

但它在“840”和“1290”之间。

我注意到只有在“720”之前或等于的数字给出了结果,所以它没有考虑我查询的第二部分(在 OR 之后)。为什么 ?谢谢。

【问题讨论】:

    标签: mysql sql json


    【解决方案1】:

    我的第一个想法是,那些JSON_EXTRACT 最终值是以整数还是字符串形式返回的?从我的测试来看,它正在返回字符串。因此,当您在字符串上使用“

    SELECT *
    FROM `service_provider`
    WHERE ((JSON_EXTRACT(`opening_hours`, '$."3"."begin"."min_hour"') <= '720' 
            AND '720' <= JSON_EXTRACT(`opening_hours`, '$."3"."begin"."max_hour"')) 
          OR (JSON_EXTRACT(`opening_hours`, '$."3"."end"."min_hour"') <= '720' 
              AND '720' <= JSON_EXTRACT(`opening_hours`, '$."3"."end"."max_hour"')));
    

    这个返回结果是因为你使用OR和第一个条件

    (JSON_EXTRACT(`opening_hours`, '$."3"."begin"."min_hour"') <= '720' 
            AND '720' <= JSON_EXTRACT(`opening_hours`, '$."3"."begin"."max_hour"')
    

    true,因为{"max_hour": "720", "min_hour": "420"} 都等于或小于720。嗯,更像是“7”大于“4”或类似于“7”。如果您删除OR 中的第一个条件会怎样:

    SELECT *
    FROM `service_provider`
    WHERE (JSON_EXTRACT(`opening_hours`, '$."3"."end"."min_hour"') <= '720' 
              AND '720' <= JSON_EXTRACT(`opening_hours`, '$."3"."end"."max_hour"'));
    

    这不会返回任何东西,因为在第一次比较中,"end"."min_hour" 返回了840,因此“8”大于“7”并且第二个条件 "end"."max_hour" 的值 1290 被识别为更小,因为“1”小于“7”。

    我想你明白了。由于这是比较字符串,所以总是首先比较值中的第一个字符。

    解决当前问题的一种快速解决方法是将JSON_EXTRACT 值转换为整数。我的建议:

    SELECT *
    FROM `service_provider`
    WHERE ((JSON_EXTRACT(`opening_hours`, '$."3"."begin"."min_hour"')+0 <= 1200
             AND 1200 <= JSON_EXTRACT(`opening_hours`, '$."3"."begin"."max_hour"')+0) 
          OR (JSON_EXTRACT(`opening_hours`, '$."3"."end"."min_hour"')+0 <= 1200 
               AND 1200 <= JSON_EXTRACT(`opening_hours`, '$."3"."end"."max_hour"')+0));
    

    JSON_EXTRACT 值的末尾添加+0 将快速将字符串转换为整数,您不妨从'1200' 中删除'

    如果您想查看从JSON 提取并使用它的返回值,您可以将它们全部移动到SELECT 并使用HAVING 进行比较,例如:

    SELECT JSON_EXTRACT(`opening_hours`, '$."3"."begin"."min_hour"')+0 bmin,
           JSON_EXTRACT(`opening_hours`, '$."3"."begin"."max_hour"')+0 bmax,
           JSON_EXTRACT(`opening_hours`, '$."3"."end"."min_hour"')+0 emin,
           JSON_EXTRACT(`opening_hours`, '$."3"."end"."max_hour"')+0 emax
    FROM `service_provider`
    HAVING ((bmin <= 1200 and  1200 <= bmax) or (emin <= 1200 and 1200 <= emax))
    

    Here is a fiddle of my tests

    【讨论】:

    • 这里是 datatype comparison 文档,它解释了比较字符串时会发生什么,虽然这是一个 oracle 文档,但我认为在不同的 DBMS 中它们会有类似的规则。还是值得一看的。
    猜你喜欢
    • 1970-01-01
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-23
    • 2013-07-14
    相关资源
    最近更新 更多