MySQL LIKE IN ()?

273

Ma requête actuelle ressemble à ceci:

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

J'ai fait quelques recherches et je ne trouve rien de similaire à un LIKE IN () - je l'imagine fonctionner comme ceci:

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

Des idées? Suis-je en train de penser au problème dans le mauvais sens - une commande obscure que je n'ai jamais vue.

Journal de communauté MySQL 5.0.77

Michael Wales
la source
1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Gjermund Dahl du
2
FIND_IN_SET n'accepte pas les caractères génériques comme%
Sebastián Grignoli

Réponses:

454

Un REGEXP pourrait être plus efficace, mais il faudrait le comparer pour être sûr, par exemple

SELECT * from fiberbox where field REGEXP '1740|1938|1940'; 
Paul Dixon
la source
2
J'aime cette réponse - rapide, simple, a obtenu toutes les "options" en une seule ligne comme je le voulais (facile à modifier). Sur le petit ensemble de résultats que je cible, aucune diminution des performances.
Michael Wales
51
Plus d'un million de lignes dans ma table. REGEX autour de 0,0009 et LIKE autour de 0,0005. Si plus de 5 REGEX, autour de 0,0012 ...
David Bélanger
10
J'avais un problème où REGEXPc'était excessivement lent, mais j'avais besoin de la flexibilité de REGEXP pour affiner mon jeu de résultats plus que ce que LIKEje pouvais fournir. J'ai trouvé une solution hybride où j'ai utilisé les deux LIKEet REGEXP; bien que la REGEXPportion soit suffisante pour me donner les résultats corrects, l'utilisation LIKEde MySQL a également permis de réduire considérablement l'ensemble de résultats avant d'avoir à utiliser les REGEXPcritères plus lents .
mpen
1
Pour obtenir la valeur d'expression régulière à partir d'une colonne:(select group_concat(myColumn separator '|') from..)
daVe
5
Ajout aux données de performance. Sur MySql 5.5 dans un tableau avec 229 millions de lignes, une recherche de 3 caractères ancrée à gauche de 1 terme: REGEXP: 16s, LIKE: 8.5s; 2 termes: REGEXP: 22,1 s, COMME: 9,69; '^ (hémoglobine | hématr? ocrit). *' vs 3 terme comme: REGEXP: 36,3, COMME: 9.59.
Jesse Clark
181

La réponse de Paul Dixon a brillamment fonctionné pour moi. Pour ajouter à cela, voici quelques choses que j'ai observées pour ceux qui souhaitent utiliser REGEXP:

Pour réaliser plusieurs filtres LIKE avec des caractères génériques:

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

Utilisez l'alternative REGEXP:

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

Les valeurs entre guillemets REGEXP et entre les | Les opérateurs (OR) sont traités comme des caractères génériques. En règle générale, REGEXP nécessite des expressions génériques telles que (. *) 1740 (. *) Pour fonctionner en tant que% 1740%.

Si vous avez besoin de plus de contrôle sur le placement du caractère générique, utilisez certaines de ces variantes:

Pour réaliser COMME avec le placement contrôlé de caractères génériques:

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

Utilisation:

SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
  • Placer ^ devant la valeur indique le début de la ligne.

  • Placer $ après la valeur indique la fin de la ligne.

  • Le placement (. *) Se comporte un peu comme le caractère générique%.

  • Le . indique n'importe quel caractère, sauf les sauts de ligne. Placement. inside () avec * (. *) ajoute un motif répétitif indiquant n'importe quel nombre de caractères jusqu'à la fin de la ligne.

Il existe des moyens plus efficaces d'affiner des correspondances spécifiques, mais cela nécessite un examen plus approfondi des expressions régulières. REMARQUE: tous les modèles d'expression régulière ne semblent pas fonctionner dans les instructions MySQL. Vous devrez tester vos modèles et voir ce qui fonctionne.

Enfin, pour réaliser plusieurs filtres LIKE et 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';

Utilisez l'alternative REGEXP:

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

OU Alternative mixte:

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

Remarquez que j'ai séparé l'ensemble NOT dans un filtre WHERE distinct. J'ai expérimenté l'utilisation de modèles de négation, de modèles prospectifs, etc. Cependant, ces expressions ne semblaient pas donner les résultats souhaités. Dans le premier exemple ci-dessus, j'utilise ^ 9999 $ pour indiquer la correspondance exacte. Cela vous permet d'ajouter des correspondances spécifiques avec des correspondances génériques dans la même expression. Cependant, vous pouvez également mélanger ces types d'instructions comme vous pouvez le voir dans le deuxième exemple répertorié.

En ce qui concerne les performances, j'ai effectué quelques tests mineurs sur une table existante et je n'ai trouvé aucune différence entre mes variations. Cependant, j'imagine que les performances pourraient être un problème avec des bases de données plus grandes, des champs plus grands, un plus grand nombre d'enregistrements et des filtres plus complexes.

Comme toujours, utilisez la logique ci-dessus car cela a du sens.

Si vous voulez en savoir plus sur les expressions régulières, je recommande www.regular-expressions.info comme bon site de référence.

David Carroll
la source
Gardez à l'esprit qu'un champ avec la valeur NULL ne correspondra pas à REGEXP. Vous pouvez utiliser IFNULL pour résoudre ce problème. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'
@DanyMarcoux Que faire si je veux utiliser (. *) Mais qu'il devrait se comporter comme FIELDNAME LIKE '%%', comment l'utiliser avec regexp, de sorte que lorsqu'une chaîne vide est passée. il devrait récupérer tous les enregistrements ..
shzyincu
Le champ WHERE NOT LIKE '% 1940%' OU le champ NOT LIKE 'test%' renverra toujours toutes les lignes. Cela a peut-être contribué à ne pas produire les résultats souhaités que vous avez mentionnés?
Herbert Van-Vliet
14

Vous pouvez créer une vue en ligne ou une table temporaire, la remplir avec vos valeurs et émettre ceci:

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

Cependant, cela peut vous renvoyer plusieurs lignes pour un fiberboxqui ressemble à quelque chose '1740, 1938', donc cette requête peut mieux vous convenir:

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
la source
13

Manière d'expression rationnelle avec liste de valeurs

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

Désolé, il n'y a aucune opération similaire à LIKE INdans mysql.

Si vous souhaitez utiliser l'opérateur LIKE sans jointure, vous devrez le faire de cette façon:

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

Vous savez, MySQL n'optimisera pas cette requête, pour info.

gahooa
la source
4

Notez simplement à quiconque essaie le REGEXP d'utiliser la fonctionnalité "LIKE IN".

IN vous permet de faire:

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

Dans REGEXP, cela ne fonctionnera pas

REGEXP '
val1$|
val2$|
val3$
'

Il doit être sur une ligne comme celle-ci:

REGEXP 'val1$|val2$|val3$'
Shaakir
la source
3

Retourner les opérandes

'a,b,c' like '%'||field||'%'
Ed Heal
la source
2
lorsque vous avez un champ explicitement serait égal à quelque chose par exemple. un enum pour les diplômés 'a', 'b', 'c' mais pas ab, ac ou bc create table x(en enum('a,b,c')));insert into x values('a'),('b') en est seulement a ou b faire cette méthode en retournant les commandes select * from, x where 'a,c' like concat('%',en,'%')peut être plus sûr dans SQL Injunction pas besoin d'échapper à des caractères comme $ ^ etc.
Ce n'est PAS équivalent et NE FONCTIONNERA PAS pour les cas généraux. Si vous saviez que cela fieldne pouvait être qu'exactement a, bou calors vous devriez utiliser field IN ('a', 'b', 'c'). Mais dans les cas généraux, cela ne peut JAMAIS remplacer field LIKE '%a%' OR field LIKE '%b%' OR ...car le champ lui-même peut être quelque chose comme magicce qui rendrait 'magic' LIKE '%a%'vrai mais l'expression est 'a,b,c' LIKE '%magic%'fausse.
ADTC
2

Ce serait correct:

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

Juste un petit conseil:

Je préfère utiliser la variante RLIKE (exactement la même commande que REGEXP ) car elle ressemble plus à du langage naturel et est plus courte; eh bien, juste 1 caractère.

Le préfixe "R" est pour Reg. Exp., Bien sûr.

Raúl Moreno
la source
0

Vous pouvez obtenir le résultat souhaité à l'aide d' expressions régulières .

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

Nous pouvons tester la requête ci-dessus, veuillez cliquer sur SQL fiddle

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

Nous pouvons tester la requête ci-dessus, veuillez cliquer sur SQL fiddle

ZIJ
la source
1
Il s'agit d'une expression régulière incorrecte. [...]est un jeu de caractères , ce qui signifie que l'un des caractères du jeu suffit pour être considéré comme une correspondance. Ainsi , toute valeur avec les chiffres » 0, 1, 3, 4, 7, 8, 9ou le |caractère pipe correspondra à ce sujet .
Martijn Pieters