MySQL LIKE IN ()?

273

Moje obecne zapytanie wygląda następująco:

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

Rozejrzałem się i nie mogę znaleźć czegoś podobnego do LIKE IN () - wyobrażam sobie, że działa to tak:

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

Jakieś pomysły? Czy po prostu myślę o problemie w niewłaściwy sposób - jakieś niejasne polecenie, którego nigdy nie widziałem.

MySQL 5.0.77-dziennik społeczności

Michael Wales
źródło
1
WHERE FIND_IN_SET(f.fiberbox, "1740,1938,1940")
Gjermund Dahl
2
FIND_IN_SET nie akceptuje symboli wieloznacznych, takich jak%
Sebastián Grignoli

Odpowiedzi:

453

REGEXP może być bardziej skuteczny, ale trzeba by benchmarku to, aby mieć pewność, np

SELECT * from fiberbox where field REGEXP '1740|1938|1940'; 
Paul Dixon
źródło
2
Podoba mi się ta odpowiedź - szybko, prosto, mam wszystkie „opcje” w jednym wierszu, tak jak chciałem (łatwe do edycji). Na niewielkim zestawie wyników, na który celuję, nie ma żadnego spadku wydajności.
Michael Wales
51
Ponad milion wierszy w moim stole. REGEX wokół 0,0009 i LIKE wokół 0,0005. Jeśli więcej niż 5 REGEX, około 0,0012 ...
David Bélanger,
10
Miałem problem, który REGEXPbył zbyt powolny, ale potrzebowałem elastyczności REGEXP, aby zawęzić mój zestaw wyników bardziej niż LIKEmógłbym to zapewnić. Wymyśliłem rozwiązanie hybrydowe, gdzie użyłem zarówno LIKEa REGEXP; pomimo tego, że REGEXPczęść jest wystarczająca do uzyskania poprawnych wyników, użycie LIKErównież pozwoliło MySQL na znaczne zmniejszenie zestawu wyników przed użyciem wolniejszych REGEXPkryteriów.
mpen
1
Aby uzyskać wartość (select group_concat(myColumn separator '|') from..)
wyrażenia regularnego
5
Dodawanie do danych o wydajności. Na MySql 5.5 w tabeli z 229 milionami wierszy zakotwiczono 1 termin 3-znakowe wyszukiwanie: REGEXP: 16s, LIKE: 8,5s; 2 warunki: REGEXP: 22,1s, LIKE: 9,69; „^ (hemoglobina | hematr? ocrit). *” vs 3 określenie, takie jak: REGEXP: 36,3, JAK: 9,59.
Jesse Clark,
181

Odpowiedź Paula Dixona działała dla mnie znakomicie. Aby dodać do tego, oto kilka rzeczy, które zauważyłem dla osób zainteresowanych używaniem REGEXP:

Aby osiągnąć wiele filtrów LIKE za pomocą symboli wieloznacznych:

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

Użyj alternatywy REGEXP:

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

Wartości w cudzysłowach REGEXP i między | Operatory (OR) są traktowane jak symbole wieloznaczne. Zazwyczaj REGEXP wymaga wyrażeń wieloznacznych, takich jak (. *) 1740 (. *), Aby działał jako% 1740%.

Jeśli potrzebujesz większej kontroli nad rozmieszczeniem symbolu wieloznacznego, skorzystaj z niektórych z tych wariantów:

Aby osiągnąć LIKE dzięki kontrolowanemu rozmieszczaniu symboli wieloznacznych:

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

Posługiwać się:

SELECT * FROM fiberbox WHERE field REGEXP '^1740 |1938 $|1940 (.*) test';
  • Umieszczenie ^ przed wartością wskazuje początek linii.

  • Umieszczenie $ po wartości oznacza koniec wiersza.

  • Umieszczanie (. *) Działa podobnie jak% symbol wieloznaczny.

  • The. wskazuje dowolny pojedynczy znak, z wyjątkiem podziałów linii. Umieszczanie inside () z * (. *) dodaje powtarzający się wzór wskazujący dowolną liczbę znaków do końca linii.

Istnieją bardziej wydajne sposoby zawężania określonych dopasowań, ale wymaga to dokładniejszej oceny wyrażeń regularnych. UWAGA: Nie wszystkie wzorce wyrażeń regularnych wydają się działać w instrukcjach MySQL. Musisz przetestować swoje wzorce i zobaczyć, co działa.

Wreszcie, aby osiągnąć wiele filtrów LIKE i 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';

Użyj alternatywy REGEXP:

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

LUB Mieszana alternatywa:

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

Zauważ, że oddzieliłem zestaw NIE w osobnym filtrze GDZIE. Eksperymentowałem z wykorzystaniem wzorów negujących, wzorów przyszłościowych i tak dalej. Jednak te wyrażenia nie przyniosły pożądanych rezultatów. W pierwszym przykładzie powyżej używam ^ 9999 $, aby wskazać dokładne dopasowanie. Umożliwia to dodawanie określonych dopasowań za pomocą symboli wieloznacznych w tym samym wyrażeniu. Można jednak również mieszać te typy instrukcji, jak widać w drugim wymienionym przykładzie.

Jeśli chodzi o wydajność, przeprowadziłem kilka drobnych testów na istniejącej tabeli i nie znalazłem żadnych różnic między moimi odmianami. Jednak wydaje mi się, że wydajność może być problemem w przypadku większych baz danych, większych pól, większej liczby rekordów i bardziej złożonych filtrów.

Jak zawsze, użyj powyższej logiki, ponieważ ma to sens.

Jeśli chcesz dowiedzieć się więcej o wyrażeniach regularnych, polecam www.regular-expressions.info jako dobrą stronę referencyjną.

David Carroll
źródło
Pamiętaj, że pole o wartości NULL nie będzie pasowało do REGEXP. Możesz użyć IFNULL, aby rozwiązać ten problem. WHERE IFNULL(field, '') NOT REGEXP '1740 | 1938'
@DanyMarcoux Co zrobić, jeśli chcę użyć (. *), Ale powinien on zachowywać się jak FIELDNAME LIKE „%%”, jak używać go z wyrażeniem regularnym, aby po przekazaniu pustego łańcucha. powinien pobrać wszystkie rekordy.
shzyincu,
Pole WHERE NOT LIKE '% 1940%' LUB pole NOT LIKE 'test%' zawsze zwraca wszystkie wiersze. Może to mogło przyczynić się do nierealizacji wspomnianych przez Ciebie pożądanych rezultatów?
Herbert Van-Vliet
14

Możesz utworzyć widok wbudowany lub tabelę tymczasową, wypełnić go swoimi wartościami i wydać to:

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

To jednak może zwrócić ci wiele wierszy dla fiberboxczegoś '1740, 1938', co jest podobne , więc to zapytanie może lepiej ci pasować:

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
źródło
13

Ponowne wyodrębnianie z listą wartości

SELECT * FROM table WHERE field regexp concat_ws("|",
"111",
"222",
"333");
użytkownik136379
źródło
7

Przepraszamy, nie ma podobnej operacji jak LIKE INw mysql.

Jeśli chcesz używać operatora LIKE bez łączenia, musisz to zrobić w ten sposób:

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

Wiesz, MySQL nie zoptymalizuje tego zapytania, FYI.

gahooa
źródło
4

Pamiętaj tylko, że każdy, kto spróbuje użyć REGEXP, aby użyć funkcji „LIKE IN”.

IN pozwala na:

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

W REGEXP to nie zadziała

REGEXP '
val1$|
val2$|
val3$
'

Musi być w jednym wierszu:

REGEXP 'val1$|val2$|val3$'
Shaakir
źródło
3

Odwróć operandy

'a,b,c' like '%'||field||'%'
Ed Heal
źródło
2
gdy masz jakieś pole, jawnie byłoby coś równać np. wyliczenie dla stopni „a”, „b”, „c”, ale nie ab, ac lub bc create table x(en enum('a,b,c')));insert into x values('a'),('b') en jest tylko a lub b wykonujący tę metodę przez odwracanie oprandów, select * from, x where 'a,c' like concat('%',en,'%')może być bezpieczniejszy w SQL Injunction bez potrzeby uciekania przed charakterem, takim jak $ ^ itd.
To NIE jest równoważne i NIE DZIAŁA w ogólnych przypadkach. Jeśli wiesz, że fieldmoże to być tylko dokładnie a, blub cpowinieneś użyć field IN ('a', 'b', 'c'). Ale w ogólnych przypadkach NIGDY nie można tego zastąpić, field LIKE '%a%' OR field LIKE '%b%' OR ...ponieważ samo pole może być czymś, magicco sprawiłoby, że 'magic' LIKE '%a%'prawda, ale wyrażenie 'a,b,c' LIKE '%magic%'fałszywe.
ADTC
2

To byłoby poprawne:

SELECT * FROM table WHERE field regexp concat_ws("|",(
"111",
"222",
"333"
));
Edmhs
źródło
2

Mała wskazówka:

Wolę używać wariantu RLIKE (dokładnie to samo polecenie co REGEXP ), ponieważ brzmi bardziej jak język naturalny i jest krótszy; cóż, tylko 1 znak.

Prefiks „R” dotyczy Reg. Exp., Oczywiście.

Raúl Moreno
źródło
0

Możesz uzyskać pożądany wynik za pomocą wyrażeń regularnych .

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

Możemy przetestować powyższe zapytanie, kliknij skrzypce SQL

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

Możemy przetestować powyższe zapytanie, kliknij skrzypce SQL

ZIJ
źródło
1
To niepoprawne wyrażenie regularne. [...]to zestaw znaków , co oznacza, że ​​dowolna z postaci w zestawie jest wystarczająca, aby być postrzegana jako dopasowanie. Więc dowolną wartość z cyfr ' 0, 1, 3, 4, 7, 8, 9lub |postać rura będzie pasował do tego.
Martijn Pieters