MySQL LIKE IN ()?


273

La mia domanda attuale è simile alla seguente:

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

Mi sono guardato attorno e non trovo nulla di simile a un LIKE IN () - Immagino che funzioni così:

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

Qualche idea? Sto solo pensando al problema nel modo sbagliato - qualche oscuro comando che non ho mai visto.

MySQL 5.0.77-community-log


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

2
FIND_IN_SET non accetta caratteri jolly come%
Sebastián Grignoli,

Risposte:


454

Un REGEXP potrebbe essere più efficiente, ma dovresti confrontarlo per sicurezza, ad es

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

2
Mi piace questa risposta: veloce, semplice, ho tutte le "opzioni" in una riga come volevo (facile da modificare). Sul piccolo set di risultati che sto prendendo di mira, nessuna riduzione delle prestazioni.
Michael Wales,

51
Oltre 1 milione di righe nella mia tabella. REGEX intorno a 0.0009 e COME intorno a 0.0005. Se più di 5 REGEX, intorno a 0,0012 ...
David Bélanger il

10
Ho avuto un problema in cui REGEXPera proibitivamente lento, ma avevo bisogno della flessibilità di REGEXP per restringere il mio set di risultati più di quanto LIKEpotesse fornire. Ho trovato una soluzione ibrida in cui ho usato entrambi LIKEe REGEXP; nonostante la REGEXPparte sia sufficiente a darmi i risultati corretti, l'utilizzo ha LIKEpermesso anche a MySQL di ridurre considerevolmente il set di risultati prima di dover utilizzare i REGEXPcriteri più lenti .
apre il

1
Per ottenere il valore regexp da una colonna:(select group_concat(myColumn separator '|') from..)
daVe,

5
Aggiunta ai dati sulle prestazioni. Su MySql 5.5 in una tabella con 229 M righe, una ricerca a 1 carattere ancorata a sinistra di 1 termine: REGEXP: 16s, LIKE: 8.5s; 2 termini: REGEXP: 22.1s, COME: 9.69; '^ (emoglobina | ematr? ocrito). *' vs 3 termini come: REGEXP: 36.3, COME: 9.59.
Jesse Clark,

181

La risposta di Paul Dixon ha funzionato perfettamente per me. Per aggiungere a questo, ecco alcune cose che ho osservato per coloro che sono interessati all'utilizzo di REGEXP:

Per realizzare più filtri LIKE con i caratteri jolly:

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

Usa l'alternativa REGEXP:

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

Valori tra virgolette REGEXP e tra | Gli operatori (OR) vengono trattati come caratteri jolly. In genere, REGEXP richiede espressioni jolly come (. *) 1740 (. *) Per funzionare come% 1740%.

Se è necessario un maggiore controllo sul posizionamento del carattere jolly, utilizzare alcune di queste varianti:

Per realizzare COME con posizionamento jolly controllato:

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

Uso:

SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
  • Posizionare ^ davanti al valore indica l'inizio della riga.

  • Il posizionamento di $ dopo il valore indica la fine della riga.

  • Il posizionamento (. *) Si comporta in modo molto simile al carattere jolly%.

  • Il . indica un singolo carattere, tranne le interruzioni di riga. Posizionamento inside () con * (. *) aggiunge uno schema ripetuto che indica un numero qualsiasi di caratteri fino alla fine della riga.

Esistono modi più efficienti per restringere le corrispondenze specifiche, ma ciò richiede una maggiore revisione delle espressioni regolari. NOTA: non tutti i pattern regex sembrano funzionare nelle istruzioni MySQL. Dovrai testare i tuoi schemi e vedere cosa funziona.

Infine, per realizzare più filtri 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';

Usa l'alternativa REGEXP:

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

O alternativa mista:

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

Si noti che ho separato il set NOT in un filtro WHERE separato. Ho sperimentato l'uso di schemi negativi, schemi lungimiranti e così via. Tuttavia, queste espressioni non sembravano produrre i risultati desiderati. Nel primo esempio sopra, uso ^ 9999 $ per indicare la corrispondenza esatta. Ciò consente di aggiungere corrispondenze specifiche con corrispondenze con caratteri jolly nella stessa espressione. Tuttavia, puoi anche mescolare questi tipi di istruzioni come puoi vedere nel secondo esempio elencato.

Per quanto riguarda le prestazioni, ho eseguito alcuni test minori su una tabella esistente e non ho riscontrato differenze tra le mie variazioni. Tuttavia, immagino che le prestazioni potrebbero essere un problema con database più grandi, campi più grandi, un numero maggiore di record e filtri più complessi.

Come sempre, usa la logica sopra come ha senso.

Se vuoi saperne di più sulle espressioni regolari, raccomando www.regular-expressions.info come buon sito di riferimento.


Tieni presente che un campo con il valore NULL non corrisponderà a REGEXP. È possibile utilizzare IFNULL per risolvere questo problema. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'

@DanyMarcoux Cosa succede se voglio usare (. *) Ma dovrebbe comportarsi come FIELDNAME COME '%%', come usarlo con regexp, in modo che quando viene passata una stringa vuota. dovrebbe recuperare tutti i record ..
shzyincu,

Il campo DOVE NON MI PIACE '% 1940%' O il campo NON MI PIACE 'test%' restituirà sempre tutte le righe. Ciò potrebbe forse aver contribuito a non produrre i risultati desiderati che hai menzionato?
Herbert Van-Vliet,

14

Puoi creare una vista incorporata o una tabella temporanea, compilarla con i tuoi valori ed emettere questo:

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

Questo, tuttavia, può restituirti più righe per fiberboxqualcosa del genere '1740, 1938', quindi questa query può adattarti meglio:

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

Riscopri la strada con un elenco di valori

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

7

Siamo spiacenti, non esiste un'operazione simile a LIKE INin mysql.

Se desideri utilizzare l'operatore LIKE senza un join, dovrai farlo in questo modo:

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

Sai, MySQL non ottimizzerà quella query, FYI.


4

Nota solo a chiunque cerchi REGEXP di utilizzare la funzionalità "COME IN".

IN ti consente di fare:

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

In REGEXP questo non funzionerà

REGEXP '
val1$|
val2$|
val3$
'

Deve essere in una riga come questa:

REGEXP 'val1$|val2$|val3$'

3

Capovolgi operandi

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

2
quando hai un campo esplicitamente equivarrebbe ad es. un enum per grads 'a', 'b', 'c' ma non ab, ac o bc create table x(en enum('a,b,c')));insert into x values('a'),('b') en è solo a o b che fa questo metodo lanciando oprands select * from, x where 'a,c' like concat('%',en,'%')può essere più sicuro in SQL Injunction, non c'è bisogno di sfuggire a personaggi come $ ^ ecc.

Questo NON è equivalente e NON FUNZIONA in casi generali. Se sapessi che fieldpuò essere solo esattamente a, bo callora dovresti usare field IN ('a', 'b', 'c'). Ma in generale, questo non può MAI sostituire field LIKE '%a%' OR field LIKE '%b%' OR ...perché il campo stesso può essere qualcosa del genere magicche renderebbe 'magic' LIKE '%a%'vero ma l'espressione 'a,b,c' LIKE '%magic%'falsa.
ADTC

2

Questo sarebbe corretto:

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

2

Solo un piccolo consiglio:

Preferisco usare la variante RLIKE (esattamente lo stesso comando di REGEXP ) in quanto sembra più un linguaggio naturale ed è più breve; bene, solo 1 carattere.

Il prefisso "R" è per Reg. Exp., Ovviamente.


0

Puoi ottenere il risultato desiderato con l'aiuto delle espressioni regolari .

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

Siamo in grado di testare la query sopra, fare clic su violino SQL

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

Siamo in grado di testare la query sopra, fare clic su violino SQL


1
Questa è un'espressione regolare errata. [...]è un set di caratteri , il che significa che uno qualsiasi dei personaggi nel set è sufficiente per essere visto come una partita. Quindi, qualsiasi valore con le cifre ' 0, 1, 3, 4, 7, 8, 9o il |carattere pipe corrisponderà questo.
Martijn Pieters
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.