Como o MySQL ()?

273

Minha consulta atual é assim:

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

Eu olhei em volta e não consigo encontrar nada parecido com um LIKE IN () - eu imagino que funcione assim:

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

Alguma ideia? Estou apenas pensando no problema da maneira errada - algum comando obscuro que eu nunca vi.

MySQL 5.0.77-community-log

Michael Wales
fonte
1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Gjermund Dahl 30/10
2
FIND_IN_SET não aceita curingas como%
Sebastián Grignoli 29/10

Respostas:

454

Um REGEXP pode ser mais eficiente, mas você precisa compará-lo para ter certeza, por exemplo,

SELECT * from fiberbox where field REGEXP '1740|1938|1940'; 
Paul Dixon
fonte
2
Eu gosto desta resposta - rápida, simples, recebi todas as "opções" em uma linha como eu queria (fácil de editar). No pequeno conjunto de resultados que estou almejando, não há redução no desempenho.
Michael Wales
51
Mais de 1 milhão de linhas na minha mesa. REGEX em torno de 0,0009 e LIKE em torno de 0,0005. Se mais de 5 REGEX, arround 0,0012 ...
David Bélanger
10
Eu tive um problema em que REGEXPera proibitivamente lento, mas precisava da flexibilidade do REGEXP para restringir ainda mais o meu conjunto de resultados LIKE. Eu vim com uma solução híbrida onde usei ambos LIKEe REGEXP; apesar da REGEXPparte ser suficiente para me fornecer os resultados corretos, o LIKEMySQL também permitiu reduzir o conjunto de resultados consideravelmente antes de ter que usar os REGEXPcritérios mais lentos .
MPEN
1
Para obter o valor regexp de uma coluna:(select group_concat(myColumn separator '|') from..)
daVe 28/11
5
Adicionando aos dados de desempenho. No MySql 5.5 em uma tabela com 229 milhões de linhas, um termo à esquerda 1 ancorou 3 caracteres de pesquisa: REGEXP: 16s, LIKE: 8.5s; 2 termos: REGEXP: 22.1s, COMO: 9.69; '^ (hemoglobina | hematr? ocrit). *' vs 3 termos como: REGEXP: 36.3, COMO: 9,59.
Jesse Clark
181

A resposta de Paul Dixon funcionou brilhantemente para mim. Para adicionar isso, aqui estão algumas coisas que observei para os interessados ​​em usar o REGEXP:

Para realizar vários filtros LIKE com caracteres curinga:

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

Use a alternativa REGEXP:

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

Valores entre aspas REGEXP e entre os | (OR) são tratados como curingas. Normalmente, o REGEXP exigirá expressões curinga como (. *) 1740 (. *) Para funcionar como% 1740%.

Se você precisar de mais controle sobre o posicionamento do curinga, use algumas destas variantes:

Para realizar o LIKE com o posicionamento curinga controlado:

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

Usar:

SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
  • Colocar ^ na frente do valor indica o início da linha.

  • Colocar $ após o valor indica o fim da linha.

  • A colocação (. *) Se comporta como o curinga%.

  • O . indica qualquer caractere único, exceto quebras de linha. Colocação. inside () com * (. *) adiciona um padrão de repetição indicando qualquer número de caracteres até o final da linha.

Existem maneiras mais eficientes de restringir correspondências específicas, mas isso requer mais revisão das Expressões Regulares. NOTA: Nem todos os padrões de expressão regular parecem funcionar nas instruções do MySQL. Você precisará testar seus padrões e ver o que funciona.

Por fim, para realizar vários filtros LIKE e 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';

Use a alternativa REGEXP:

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

OU Alternativa mista:

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

Observe que eu separei o conjunto NOT em um filtro WHERE separado. Eu experimentei usar padrões de negação, padrões de previsão e assim por diante. No entanto, essas expressões não parecem produzir os resultados desejados. No primeiro exemplo acima, eu uso ^ 9999 $ para indicar a correspondência exata. Isso permite adicionar correspondências específicas com correspondências curinga na mesma expressão. No entanto, você também pode misturar esses tipos de instruções, como você pode ver no segundo exemplo listado.

Em relação ao desempenho, executei alguns testes menores em uma tabela existente e não encontrei diferenças entre minhas variações. No entanto, imagino que o desempenho possa ser um problema com bancos de dados maiores, campos maiores, maior número de registros e filtros mais complexos.

Como sempre, use a lógica acima, pois faz sentido.

Se você quiser aprender mais sobre expressões regulares, recomendo www.regular-expressions.info como um bom site de referência.

David Carroll
fonte
Lembre-se de que um campo com o valor NULL não corresponderá a REGEXP. Você pode usar IFNULL para resolver esse problema. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'
@DanyMarcoux E se eu quiser usar (. *), Mas ele deve agir como FIELDNAME LIKE '%%', como usá-lo com regexp, para que quando uma string vazia for passada. deve buscar todos os registros ..
shzyincu 28/07
O campo WHERE NOT LIKE '% 1940%' OU campo NOT LIKE 'test%' sempre retornará todas as linhas. Talvez isso tenha contribuído para não produzir os resultados desejados que você mencionou?
Herbert Van-Vliet
14

Você pode criar uma exibição em linha ou uma tabela temporária, preenchê-la com seus valores e emitir o seguinte:

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

No entanto, isso pode retornar várias linhas para uma fiberboxque é algo parecido '1740, 1938', portanto, essa consulta pode ser melhor para você:

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
        )
Quassnoi
fonte
13

Regexp maneira com lista de valores

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

Desculpe, não há operação semelhante à LIKE INdo mysql.

Se você quiser usar o operador LIKE sem uma junção, precisará fazer o seguinte:

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

Você sabe, o MySQL não otimizará essa consulta, FYI.

gahooa
fonte
4

Apenas observe quem está tentando o REGEXP para usar a funcionalidade "LIKE IN".

IN permite que você faça:

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

No REGEXP, isso não funcionará

REGEXP '
val1$|
val2$|
val3$
'

Tem que estar em uma linha como esta:

REGEXP 'val1$|val2$|val3$'
Shaakir
fonte
3

Operandos flip

'a,b,c' like '%'||field||'%'
Ed Heal
fonte
2
quando você tem algum campo explicitamente seria algo igual, por exemplo. um enum para graduados 'a', 'b', 'c' , mas não ab, ac ou bc create table x(en enum('a,b,c')));insert into x values('a'),('b') en apenas a ou b fazer esse método lançando oprands select * from, x where 'a,c' like concat('%',en,'%')pode ser mais seguro em Liminar SQL há necessidade de escapar charactors como $ ^ etc.
Isso NÃO é equivalente e NÃO FUNCIONA para casos gerais. Se você sabia que fieldsó pode ser exatamente a, bou centão você deve usar field IN ('a', 'b', 'c'). Mas, em casos gerais, isso NUNCA pode substituir, field LIKE '%a%' OR field LIKE '%b%' OR ...pois o próprio campo pode ser algo magicque tornaria 'magic' LIKE '%a%'verdadeiro, mas a expressão 'a,b,c' LIKE '%magic%'falsa.
ADTC
2

Isso seria correto:

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

Apenas uma pequena dica:

Prefiro usar a variante RLIKE (exatamente o mesmo comando do REGEXP ), pois soa mais como linguagem natural e é mais curta; bem, apenas 1 caractere.

O prefixo "R" é para Reg. Exp., É claro.

Raúl Moreno
fonte
0

Você pode obter o resultado desejado com a ajuda de expressões regulares .

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

Podemos testar a consulta acima, por favor clique SQL violino

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

Podemos testar a consulta acima, por favor clique SQL violino

ZIJ
fonte
1
Esta é uma expressão regular incorreta. [...]é um conjunto de caracteres , o que significa que qualquer um dos caracteres do conjunto é suficiente para ser visto como uma correspondência. Portanto, qualquer valor com os dígitos " 0, 1, 3, 4, 7, 8, 9ou o |caractere pipe irá corresponder a isso.
Martijn Pieters