¿MySQL COMO EN ()?

273

Mi consulta actual se ve así:

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

Miré un poco y no encuentro nada similar a LIKE IN (). Imagino que funcione así:

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

¿Algunas ideas? ¿Estoy pensando en el problema de la manera incorrecta? Algún comando oscuro que nunca he visto.

MySQL 5.0.77-registro-comunidad

Michael Wales
fuente
1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Gjermund Dahl el
2
FIND_IN_SET no acepta comodines como%
Sebastián Grignoli

Respuestas:

454

Un REGEXP podría ser más eficiente, pero tendría que compararlo para asegurarse, por ejemplo

SELECT * from fiberbox where field REGEXP '1740|1938|1940'; 
Paul Dixon
fuente
2
Me gusta esta respuesta: rápida, simple, obtuve todas las "opciones" en una línea como quería (fácil de editar). En el pequeño conjunto de resultados al que me dirijo, no hay ninguna disminución en el rendimiento.
Michael Wales
51
Más de 1 millón de filas en mi mesa. REGEX alrededor de 0.0009 y como alrededor de 0.0005. Si hay más de 5 REGEX, alrededor de 0.0012 ...
David Bélanger
10
Tuve un problema donde REGEXPera prohibitivamente lento, pero necesitaba la flexibilidad de REGEXP para reducir mi conjunto de resultados más de lo que LIKEpodía proporcionar. Se me ocurrió una solución híbrida donde usé ambos LIKEy REGEXP; a pesar de que la REGEXPporción es suficiente para darme los resultados correctos, usar LIKEMySQL también permitió reducir considerablemente el conjunto de resultados antes de tener que usar los REGEXPcriterios más lentos .
mpen
1
Para obtener el valor regexp de una columna:(select group_concat(myColumn separator '|') from..)
desde el
55
Agregando a los datos de rendimiento. En MySql 5.5 en una tabla con 229 millones de filas, 1 término dejó anclado 3 caracteres de búsqueda: REGEXP: 16s, LIKE: 8.5s; 2 términos: REGEXP: 22.1s, LIKE: 9.69; '^ (hemoglobina | hematr? ocrit). *' frente a 3 términos como: REGEXP: 36.3, ME GUSTA: 9.59.
Jesse Clark
181

La respuesta de Paul Dixon funcionó brillantemente para mí. Para agregar a esto, aquí hay algunas cosas que observé para aquellos interesados ​​en usar REGEXP:

Para lograr múltiples filtros LIKE con comodines:

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

Utilice la alternativa REGEXP:

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

Valores dentro de comillas REGEXP y entre | El operador (OR) se trata como comodines. Normalmente, REGEXP requerirá expresiones comodín como (. *) 1740 (. *) Para funcionar como% 1740%.

Si necesita más control sobre la ubicación del comodín, use algunas de estas variantes:

Para lograr LIKE con la colocación de comodines controlados:

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

Utilizar:

SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
  • Colocar ^ delante del valor indica el inicio de la línea.

  • Colocar $ después del valor indica el final de la línea.

  • Colocar (. *) Se comporta como el comodín%.

  • Los . indica cualquier carácter individual, excepto los saltos de línea. Colocación inside () con * (. *) agrega un patrón repetitivo que indica cualquier número de caracteres hasta el final de la línea.

Hay formas más eficientes de reducir coincidencias específicas, pero eso requiere una mayor revisión de las expresiones regulares. NOTA: No todos los patrones de expresiones regulares parecen funcionar en las declaraciones de MySQL. Tendrá que probar sus patrones y ver qué funciona.

Finalmente, para lograr múltiples filtros LIKE y 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';

Utilice la alternativa REGEXP:

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

O Alternativa Mixta:

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

Observe que separé el conjunto NO en un filtro WHERE separado. Experimenté con el uso de patrones de negación, patrones prospectivos, etc. Sin embargo, estas expresiones no parecían producir los resultados deseados. En el primer ejemplo anterior, uso ^ 9999 $ para indicar la coincidencia exacta. Esto le permite agregar coincidencias específicas con coincidencias comodín en la misma expresión. Sin embargo, también puede mezclar este tipo de declaraciones como puede ver en el segundo ejemplo que se enumera.

Con respecto al rendimiento, realicé algunas pruebas menores en una tabla existente y no encontré diferencias entre mis variaciones. Sin embargo, imagino que el rendimiento podría ser un problema con bases de datos más grandes, campos más grandes, mayores recuentos de registros y filtros más complejos.

Como siempre, use la lógica anterior, ya que tiene sentido.

Si desea obtener más información sobre las expresiones regulares, le recomiendo www.regular-expressions.info como un buen sitio de referencia.

David Carroll
fuente
Tenga en cuenta que un campo con el valor NULL no coincidirá con REGEXP. Puede usar IFNULL para resolver este problema. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'
@DanyMarcoux ¿Qué sucede si quiero usar (. *) Pero debería actuar como FIELDNAME LIKE '%%', cómo usarlo con regexp, de modo que cuando se pasa una cadena vacía. debería buscar todos los registros ..
shzyincu
El campo WHERE NOT LIKE '% 1940%' OR field NOT LIKE 'test%' siempre devolverá todas las filas. ¿Tal vez eso haya contribuido a no producir los resultados deseados que mencionó?
Herbert Van-Vliet
14

Puede crear una vista en línea o una tabla temporal, llenarla con sus valores y emitir esto:

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

Sin embargo, esto puede devolverle varias filas para fiberboxalgo similar '1740, 1938', por lo que esta consulta puede adaptarse mejor a usted:

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
fuente
13

Regexp forma con lista de valores

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

Lo sentimos, no hay una operación similar a LIKE INmysql.

Si desea utilizar el operador LIKE sin una unión, deberá hacerlo de esta manera:

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

Sabes, MySQL no optimizará esa consulta, para tu información.

gahooa
fuente
4

Solo tenga en cuenta que cualquiera que intente el REGEXP para usar la funcionalidad "LIKE IN"

IN le permite hacer:

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

En REGEXP esto no funcionará

REGEXP '
val1$|
val2$|
val3$
'

Tiene que estar en una línea como esta:

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

Voltear operandos

'a,b,c' like '%'||field||'%'
Ed Heal
fuente
2
cuando tienes algún campo explícitamente sería igual a algo, por ejemplo. una enumeración para graduados 'a', 'b', 'c' pero no ab, ac o bc create table x(en enum('a,b,c')));insert into x values('a'),('b') en es solo aob haciendo este método volteando oprands select * from, x where 'a,c' like concat('%',en,'%')puede ser más seguro en SQL Injunction sin necesidad de escapar de personajes como $ ^ etc.
Esto NO es equivalente y NO FUNCIONARÁ para casos generales. Si supieras que fieldsolo puede ser exactamente a, bo cdeberías usarlo field IN ('a', 'b', 'c'). Pero en casos generales, esto NUNCA puede reemplazar field LIKE '%a%' OR field LIKE '%b%' OR ...porque el campo en sí puede ser algo así como lo magicque sería 'magic' LIKE '%a%'verdadero, pero la expresión sería 'a,b,c' LIKE '%magic%'falsa.
ADTC
2

Esto sería correcto:

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

Solo un pequeño consejo:

Prefiero usar la variante RLIKE (exactamente el mismo comando que REGEXP ) ya que suena más como lenguaje natural y es más corta; bueno, solo 1 char.

El prefijo "R" es para Reg. Exp., Por supuesto.

Raúl Moreno
fuente
0

Puede obtener el resultado deseado con la ayuda de Expresiones regulares .

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

Podemos probar la consulta anterior, haga clic en violín de SQL

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

Podemos probar la consulta anterior, haga clic en violín de SQL

ZIJ
fuente
1
Esta es una expresión regular incorrecta. [...]es un conjunto de caracteres , lo que significa que cualquiera de los caracteres en el conjunto es suficiente para ser visto como una coincidencia. Así que cualquier valor con los dígitos ' 0, 1, 3,4 , 7, 8, 9o el |carácter de canalización coincidirá con esto.
Martijn Pieters