【问题标题】:MySQL LIKE IN()?MySQL喜欢在()?
【发布时间】:2010-11-10 18:09:17
【问题描述】:

我当前的查询如下所示:

SELECT * FROM fiberbox f WHERE f.fiberBox LIKE '%1740 %' OR f.fiberBox LIKE '%1938 %' OR f.fiberBox LIKE '%1940 %'

我环顾四周,找不到任何类似于 LIKE IN() 的东西 - 我设想它是这样工作的:

SELECT * FROM fiberbox f WHERE f.fiberbox LIKE IN('%140 %', '%1938 %', '%1940 %')

有什么想法吗?我是否只是以错误的方式思考问题 - 一些我从未见过的晦涩命令。

MySQL 5.0.77-community-log

【问题讨论】:

  • WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
  • FIND_IN_SET 不接受像%这样的通配符

标签: sql mysql


【解决方案1】:

你也可以这样使用:

 SELECT
    * 
FROM
    fiberbox f
    JOIN (
    SELECT
        substring_index( substring_index( '1740,1938,1940', ',', help_topic_id + 1 ), ',',- 1 ) AS sub_ 
    FROM
        mysql.help_topic 
    WHERE
        help_topic_id <(
            length( '1740,1938,1940' )- length(
            REPLACE ( '1740,1938,1940', ',', '' ))+ 1 
        ) AS b 
        ) ON f.fiberBox LIKE concat('%',
    b.sub_,
    '%')

【讨论】:

    【解决方案2】:

    你也可以这样使用:

    SELECT * FROM fiberbox WHERE fiber IN('140 ', '1938 ', '1940 ')
    

    【讨论】:

      【解决方案3】:

      请注意任何尝试使用 REGEXP 使用“LIKE IN”功能的人。

      IN 允许您这样做:

      field IN (
      'val1',
      'val2',
      'val3'
      )
      

      在 REGEXP 中这不起作用

      REGEXP '
      val1$|
      val2$|
      val3$
      '
      

      它必须像这样在一行中:

      REGEXP 'val1$|val2$|val3$'
      

      【讨论】:

        【解决方案4】:

        您可以在Regular Expressions 的帮助下获得想要的结果。

        SELECT fiberbox from fiberbox where fiberbox REGEXP '[1740|1938|1940]';
        

        我们可以测试上面的查询请点击SQL fiddle

        SELECT fiberbox from fiberbox where fiberbox REGEXP '[174019381940]';
        

        我们可以测试上面的查询请点击SQL fiddle

        【讨论】:

        • 这是一个不正确的正则表达式。 [...] 是一个字符集,这意味着该集中的任何字符都足以被视为匹配。所以 any value 与数字 '0, 1, 3, 4, 7, 8, 9| 管道字符将匹配这个。
        【解决方案5】:

        一点小提示:

        我更喜欢使用变体 RLIKE(与 REGEXP 完全相同的命令),因为它听起来更像自然语言,而且更短;好吧,只有 1 个字符。

        “R”前缀用于Reg。 Exp.,当然。

        【讨论】:

          【解决方案6】:

          这是正确的:

          SELECT * FROM table WHERE field regexp concat_ws("|",(
          "111",
          "222",
          "333"
          ));
          

          【讨论】:

            【解决方案7】:

            Paul Dixon 的回答对我来说非常有用。除此之外,对于那些对使用 REGEXP 感兴趣的人,我观察到以下几点:

            使用通配符完成多个 LIKE 过滤器:

             SELECT * FROM fiberbox WHERE field LIKE '%1740 %'
                                       OR field LIKE '%1938 %'
                                       OR field LIKE '%1940 %';  
            

            使用 REGEXP 替代方案:

             SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 |1940 ';
            

            REGEXP 引号内和 | 之间的值(OR) 运算符被视为通配符。通常,REGEXP 需要通配符表达式,例如 (.*)1740 (.*) 才能作为 %1740 % 工作。

            如果您需要对通配符的位置进行更多控制,请使用以下一些变体:

            使用受控通配符放置来完成 LIKE:

            SELECT * FROM fiberbox WHERE field LIKE '1740 %'
                                      OR field LIKE '%1938 '
                                      OR field LIKE '%1940 % test';  
            

            用途:

            SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
            
            • 将 ^ 放在值前面表示行首。

            • 将 $ 放在值后表示行尾。

            • 放置 (.*) 的行为很像 % 通配符。

            • .表示任何单个字符,换行符除外。配售。 inside () 和 * (.*) 添加一个重复模式,指示任意数字 直到行尾的字符数。

            有更有效的方法来缩小特定匹配的范围,但这需要更多地查看正则表达式。注意:并非所有正则表达式模式似乎都适用于 MySQL 语句。您需要测试您的模式,看看什么是有效的。

            最后,实现多个 LIKE 和 NOT LIKE 过滤器:

            SELECT * FROM fiberbox WHERE field LIKE '%1740 %'
                                      OR field LIKE '%1938 %'
                                      OR field NOT LIKE '%1940 %'
                                      OR field NOT LIKE 'test %'
                                      OR field = '9999';
            

            使用 REGEXP 替代方案:

            SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 |^9999$'
                                      OR field NOT REGEXP '1940 |^test ';
            

            或混合替代:

            SELECT * FROM fiberbox WHERE field REGEXP '1740 |1938 '
                                      OR field NOT REGEXP '1940 |^test '
                                      OR field NOT LIKE 'test %'
                                      OR field = '9999';
            

            请注意,我将 NOT 集分隔在单独的 WHERE 过滤器中。我尝试使用否定模式、前瞻性模式等。然而,这些表达式似乎并没有产生预期的结果。在上面的第一个示例中,我使用 ^9999$ 来表示完全匹配。这允许您在同一表达式中添加具有通配符匹配的特定匹配。但是,您也可以混合使用这些类型的语句,如列出的第二个示例所示。

            关于性能,我对现有表进行了一些小测试,发现我的变体之间没有差异。但是,我认为更大的数据库、更大的字段、更多的记录数和更复杂的过滤器可能会导致性能问题。

            和往常一样,使用上面的逻辑,因为它是有意义的。

            如果你想了解更多关于正则表达式的知识,我推荐 www.regular-expressions.info 作为一个很好的参考网站。

            【讨论】:

            • 请记住,值为 NULL 的字段与 REGEXP 不匹配。您可以使用 IFNULL 来解决此问题。 WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'
            • @DanyMarcoux 如果我想使用 (.*) 但它的行为应该像 FIELDNAME LIKE '%%' 一样,如何将它与正则表达式一起使用,以便在传递空字符串时。它应该获取所有记录..
            • WHERE 字段 NOT LIKE '%1940 %' OR field NOT LIKE 'test %' 将始终返回所有行。这可能导致没有产生您提到的预期结果?
            【解决方案8】:

            带有值列表的正则表达式方式

            SELECT * FROM table WHERE field regexp concat_ws("|",
            "111",
            "222",
            "333");
            

            【讨论】:

              【解决方案9】:

              翻转操作数

              'a,b,c' like '%'||field||'%'
              

              【讨论】:

              • 当你有一些字段时 explicitly 会等于一些东西,例如。毕业生的枚举 'a','b','c' 但不是 ab,ac 或 bc create table x(en enum('a,b,c')));insert into x values('a'),('b')en 只是 a 或 b 通过翻转操作数select * from, x where 'a,c' like concat('%',en,'%') 执行此方法可以在 SQL Injunction 中更安全,无需转义 $^ 等字符。跨度>
              • 这是不等价的,并且不适用于一般情况。 如果您知道 field 只能是 abc,那么你应该使用field IN ('a', 'b', 'c')。但在一般情况下,这永远不能替换 field LIKE '%a%' OR field LIKE '%b%' OR ...,因为字段本身可以类似于 magic,这将使 'magic' LIKE '%a%' 为真,但表达式 'a,b,c' LIKE '%magic%' 为假。
              【解决方案10】:

              REGEXP可能更高效,但您必须对其进行基准测试才能确定,例如

              SELECT * from fiberbox where field REGEXP '1740|1938|1940'; 
              

              【讨论】:

              • 我喜欢这个答案 - 快速、简单,在一行中得到了我想要的所有“选项”(易于编辑)。在我所针对的小型结果集上,性能完全没有下降。
              • 我的表中有超过 100 万行。 REGEX arround 0.0009 和 LIKE arround 0.0005。如果超过 5 个正则表达式,则 0.0012...
              • 我遇到了一个问题,REGEXP 速度非常慢,但我需要 REGEXP 的灵活性来进一步缩小我的结果集,而不是 LIKE 所能提供的。我想出了一个混合解决方案,我同时使用了LIKEREGEXP;尽管REGEXP 部分足以给我正确的结果,但使用LIKE 也允许MySQL 在不得不使用较慢的REGEXP 标准之前大大减少结果集。
              • 从列中获取正则表达式值:(select group_concat(myColumn separator '|') from..)
              • 添加到性能数据。在 MySql 5.5 上,在一个有 229M 行的表中,一个 1 术语左锚定 3 字符搜索:REGEXP: 16s, LIKE: 8.5s; 2 项:REGEXP:22.1s,LIKE:9.69; '^(hemoglobin|hematr?ocrit).*' vs 3 term like: REGEXP: 36.3, LIKE: 9.59.
              【解决方案11】:

              对不起,mysql中没有类似LIKE IN的操作。

              如果你想在没有连接的情况下使用 LIKE 运算符,你必须这样做:

              (field LIKE value OR field LIKE value OR field LIKE value)
              

              您知道,MySQL 不会优化该查询,仅供参考。

              【讨论】:

                【解决方案12】:

                你可以创建一个内联视图或一个临时表,用你的值填充它并发出这个:

                SELECT  *
                FROM    fiberbox f
                JOIN    (
                        SELECT '%1740%' AS cond
                        UNION ALL
                        SELECT '%1938%' AS cond
                        UNION ALL
                        SELECT '%1940%' AS cond
                        ) с
                ON      f.fiberBox LIKE cond
                

                但是,这可能会为您返回多个行的 fiberbox,类似于 '1740, 1938',因此此查询更适合您:

                SELECT  *
                FROM    fiberbox f
                WHERE   EXISTS
                        (
                        SELECT  1
                        FROM    (
                                SELECT '%1740%' AS cond
                                UNION ALL
                                SELECT '%1938%' AS cond
                                UNION ALL
                                SELECT '%1940%' AS cond
                                ) с
                        WHERE   f.fiberbox LIKE cond
                        )
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-01-27
                  • 2019-07-03
                  • 2014-03-30
                  • 2012-03-17
                  • 2011-07-17
                  • 1970-01-01
                  相关资源
                  最近更新 更多