MySQL喜欢IN()?


273

我当前的查询如下所示:

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-社区日志


1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Gjermund Dahl

2
FIND_IN_SET不接受通配符像%
塞巴斯蒂安Grignoli

Answers:


453

一个REGEXP 可能会更有效,但你必须对它进行基准测试,以确保,如

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

2
我喜欢这个答案-快速,简单,将所有“选项”都按我的意愿放在一行中(易于编辑)。在我定位的较小结果集上,性能完全没有降低。
迈克尔·威尔士,

51
我的表格中有超过一百万行。REGEX约0.0009,LIKE约0.0005。如果再加上5个REGEX,则大约为0.0012 ...
DavidBélanger11年

10
我遇到了一个REGEXP速度过慢的问题,但是我需要REGEXP的灵活性来缩小我的结果集,使其超出LIKE可提供的范围。我想出了一个混合解决方案,在其中我同时使用了LIKEREGEXP; 尽管该REGEXP部分足以给我正确的结果,但LIKE在必须使用较慢的REGEXP条件之前,使用MySQL还可以大大减少结果集。
mpen 2012年

1
要从列中获取正则表达式值:(select group_concat(myColumn separator '|') from..)
daVe 2015年

5
添加到性能数据。在MySql 5.5中,在具有2.29亿行的表中,左1个字词锚定了3个字符搜索:REGEXP:16s,LIKE:8.5s;2个字词:REGEXP:22.1秒;喜欢:9.69;'^(hemoglobin | hematr?ocrit)。*'vs 3 term like:REGEXP:36.3,LIKE:9.59。
杰西·克拉克

181

保罗·迪克森(Paul Dixon)的回答对我来说非常出色。除此之外,对于那些对使用REGEXP感兴趣的人,我观察到了一些东西:

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

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

使用REGEXP Alternative:

 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';
  • 将^放在值的前面表示行的开始。

  • 在该值之后放置$表示行尾。

  • 放置(。*)的行为与%通配符非常相似。

  • 的。表示任何单个字符,但换行符除外。放置。在()中,带*(。*)的行将添加一个重复模式,该模式指示直到行尾的任意数量的字符。

有更有效的方法来缩小特定的匹配范围,但这需要对正则表达式进行更多的检查。注意:并非所有的正则表达式模式都可以在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 Alternative:

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';

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

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

与往常一样,请使用上面的逻辑。

如果您想了解有关正则表达式的更多信息,我建议将www.regular-expressions.info作为一个很好的参考站点。


请记住,值为NULL的字段与REGEXP不匹配。您可以使用IFNULL解决此问题。WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'

@DanyMarcoux如果我想使用(。*),但它应该像FIELDNAME LIKE'%%'一样,如何与regexp一起使用,以便在传递空字符串时使用。它应该获取所有记录
。.– shzyincu

不喜欢'%1940%'的WHERE字段或不喜欢'测试%'的字段将始终返回所有行。这可能是导致未产生您提到的预期结果的原因吗?
Herbert Van-Vliet

14

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

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
        )

13

正则表达式与值列表的方式

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

7

抱歉,没有类似的操作 LIKE IN mysql的操作。

如果要在没有联接的情况下使用LIKE运算符,则必须采用以下方式:

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

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


4

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

IN允许您执行以下操作:

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

在REGEXP中,此功能无效

REGEXP '
val1$|
val2$|
val3$
'

它必须像这样一行:

REGEXP 'val1$|val2$|val3$'

3

翻转操作数

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

2
当你有一些字段明确地等于例如。grads'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指令中可以更安全,无需转义$ ^等

这不是等效的,在一般情况下将不起作用。如果你知道,field只能是准确ab或者c那么你应该使用field IN ('a', 'b', 'c')。但在一般情况下,这永远无法替代field LIKE '%a%' OR field LIKE '%b%' OR ...,因为场本身可以是像magic这将使得'magic' LIKE '%a%'真实的,但表达'a,b,c' LIKE '%magic%'错误。
ADTC

2

这是正确的:

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

2

提示:

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

“ R”前缀用于Reg。当然可以。


0

您可以借助正则表达式获得理想的结果。

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

我们可以测试以上查询,请点击SQL小提琴

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

我们可以测试以上查询,请点击SQL小提琴


1
这是不正确的正则表达式。[...]是一个字符集,意味着该集中的任何字符都足以被视为匹配项。因此,任何值与数字“ 0134789|管道字符将匹配这一点。
马丁·彼得
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.