MySQL, как в ()?


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-community-log


1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Гермунд Даль

2
FIND_IN_SET не принимает такие символы подстановки, как%
Себастьян Гриньоли

Ответы:


454

REGEXP может быть более эффективным, но вы должны были бы эталоном это , чтобы быть уверенным, например ,

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

2
Мне нравится этот ответ - быстро, просто, я получил все «опции» в одну строку, как я хотел (легко редактировать). На небольшой набор результатов я нацеливаюсь, никакого снижения производительности вообще.
Майкл Уэльс

51
Более 1 миллиона строк в моей таблице. REGEX около 0,0009 и LIKE около 0,0005. Если больше, чем 5 REGEX, около 0,0012 ...
Дэвид Беланджер

10
У меня была проблема, которая REGEXPбыла слишком медленной, но мне нужна была гибкость REGEXP, чтобы сузить свой набор результатов дальше, чем LIKEмог бы обеспечить. Я придумал гибридное решение, в котором я использовал и то, LIKEи другое REGEXP; несмотря на то, что эта REGEXPчасть достаточна для получения правильных результатов, использование LIKEMySQL также позволило значительно сократить набор результатов, прежде чем использовать более медленные REGEXPкритерии.
mpen

1
Чтобы получить значение регулярного выражения из столбца:(select group_concat(myColumn separator '|') from..)
daVe

5
Добавление к данным производительности. На MySql 5.5 в таблице с 229M строками поиск по 1 условию слева привязан к 3 символам: REGEXP: 16 с, LIKE: 8,5 с; 2 условия: REGEXP: 22,1 с, LIKE: 9,69; '^ (гемоглобин | hematr? ocrit). *' против 3 терминов, подобных: REGEXP: 36,3, LIKE: 9,59.
Джесси Кларк

181

Ответ Пола Диксона сработал для меня блестяще. Чтобы добавить к этому, вот некоторые вещи, которые я наблюдал для тех, кто заинтересован в использовании 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 и между | (ИЛИ) оператор рассматривается как символы подстановки. Как правило, для 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 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';

Обратите внимание, что я отделил набор NOT в отдельном фильтре WHERE. Я экспериментировал с использованием отрицательных шаблонов, прогнозных шаблонов и так далее. Однако эти выражения, похоже, не дали желаемых результатов. В первом примере выше я использую ^ 9999 $, чтобы указать точное совпадение. Это позволяет добавлять конкретные совпадения с подстановочными совпадениями в одном выражении. Тем не менее, вы также можете смешивать эти типы операторов, как вы можете видеть во втором примере в списке.

Что касается производительности, я провел несколько небольших тестов по существующей таблице и не обнаружил различий между моими вариантами. Однако я думаю, что производительность может быть проблемой с большими базами данных, большими полями, большим количеством записей и более сложными фильтрами.

Как всегда, используйте логику выше, так как она имеет смысл.

Если вы хотите узнать больше о регулярных выражениях, я рекомендую www.regular-expressions.info как хороший справочный сайт.


Помните, что поле со значением NULL не будет совпадать с REGEXP. Вы можете использовать IFNULL для решения этой проблемы. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'

@DanyMarcoux Что делать, если я хочу использовать (. *), Но он должен действовать как FIELDNAME LIKE '%%', как использовать его с регулярным выражением, чтобы при передаче пустой строки. он должен получить все записи ..
shzyincu

Поле WHERE NOT LIKE «% 1940%» ИЛИ Поле NOT LIKE «test%» всегда будет возвращать все строки. Возможно, это способствовало тому, что вы не дали желаемых результатов, о которых вы упомянули?
Герберт Ван-Влит

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
когда у вас есть какое-то поле явно будет равно что-то, например. перечисление для классов '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может быть только точно a, bили 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
Это неправильное регулярное выражение. [...]является набором символов , означающим, что любого из символов в наборе достаточно, чтобы рассматривать как совпадение. Таким образом , любое значение с цифрами " 0, 1, 3, 4, 7, 8, 9или |характер трубы будет соответствовать этому.
Мартин Питерс
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.