Ciąg zapytania MySQL zawiera

307

Próbowałem dowiedzieć się, w jaki sposób mogę wykonać zapytanie za pomocą MySQL, które sprawdza, czy wartość (ciąg $haystack) w określonej kolumnie zawiera określone dane (ciąg $needle), takie jak:

mysql_query("
SELECT *
FROM `table`
WHERE `column`.contains('{$needle}')
");

W PHP funkcja jest wywoływana substr($haystack, $needle), więc może:

WHERE substr(`column`, '{$needle}')=1
arik
źródło

Odpowiedzi:

437

Właściwie dość proste:

mysql_query("
SELECT *
FROM `table`
WHERE `column` LIKE '%{$needle}%'
");

%Jest wieloznaczny dla wszelkich znaków Set (brak, jednego lub wielu). Zauważ, że może się to spowolnić w przypadku bardzo dużych zestawów danych, więc jeśli baza danych rośnie, musisz użyć indeksów pełnotekstowych.

Wolph
źródło
1
Działa to tylko wtedy, gdy używasz przygotowanego zapytania. Jeśli używasz tam prawdziwego ciągu (np. Skryptu aktualizacyjnego upłynnienia SQL), rozważ INSTR wymienione poniżej). Wynika to z faktu, że jeśli Twój ciąg zawiera%, zaczniesz z nim pasować.
Ryan Shillington
2
wiem o podobnych zapytaniach, a jednak dzisiaj chciałem dowiedzieć się, czy istnieje pewna wartość w łańcuchu w jakiejś kolumnie, w której szukałem go. Dlaczego nigdy wcześniej o tym nie myślałem?
Sizzling Code
1
czy w tym rozróżniana jest wielkość liter?
zły kiwi
2
@angry_kiwi: z column LIKE '...'tym nie rozróżnia wielkości liter, z column LIKE BINARY '...'tym jest rozróżniana
wielkość
2
Dziwi mnie, że LIKEzaproponowano sprawdzenie podciągu, ponieważ ten operator używa dwóch znaków wieloznacznych: %i _. Oznacza to, że jeśli igła $ ciągu zawiera jeden z tych znaków specjalnych, wówczas wyniki nie są zgodne z oczekiwaniami. (-1) dla tej odpowiedzi i (+1) dla odpowiedzi INSTR.
Skrol29
144

Posługiwać się:

SELECT *
  FROM `table`
 WHERE INSTR(`column`, '{$needle}') > 0

Odniesienie:

Kucyki OMG
źródło
na pewno LIKE jest szybszy niż INSTR?
Chris
17
@oedo: Zależy. LIKE %...%nie użyje indeksu, jeśli jest obecny, więc powinny być równoważne; LIKE ...%użyłby indeksu, jeśli jest obecny. Jeśli wydajność stanowi poważny problem, lepszym rozwiązaniem byłoby wyszukiwanie pełnotekstowe (FTS).
Kucyki OMG
doskonały. właśnie tego szukałem.
arik
2
Podoba mi się to rozwiązanie, ponieważ w rzeczywistości nie ma sposobu, aby posortować rzeczy według obecności podciągu z likeoperatorem. Z instrfrazą można zamówić w ten sposóbselect * from table order by instr(col1,"mystring")
Radacina
Chciałem wyszukać _ w polu i zadziałało. Dzięki
Safeer Ahmed,
53
WHERE `column` LIKE '%$needle%'
Chris
źródło
2
podczas wyszukiwania znaku _ (podkreślenie) zapytanie JAK '% _%' nie działa, z jakiegoś powodu zwraca wszystkie ciągi nawet bez _
Wojtek
1
@Wojtek _ jest znakiem wieloznacznym dla każdego pojedynczego znaku, więc jeśli chcesz wyszukać dosłowny znak podkreślenia, musisz go uciec. Zobacz zapytanie LIKE MySQL z podkreśleniem .
jkmartindale
29

Mój używa LOCATEw mysql:

LOCATE (substr, str), LOCATE (substr, str, pos)

Ta funkcja jest bezpieczna dla wielu bajtów i rozróżnia małe i wielkie litery tylko wtedy, gdy co najmniej jeden argument jest łańcuchem binarnym.

W Twoim przypadku:

mysql_query("
SELECT * FROM `table`
WHERE LOCATE('{$needle}','column') > 0
");
risnandar
źródło
11
„kolumna” powinna być kolumną (bez cudzysłowów)
Wojtek
10

Oprócz odpowiedzi z @WoLpH.

Korzystając ze LIKEsłowa kluczowego, możesz również ograniczyć kierunek, w którym pasuje ciąg. Na przykład:

Jeśli szukasz ciągu rozpoczynającego się od $needle:

... WHERE column LIKE '{$needle}%'

Jeśli szukałeś ciągu, który kończy się na $needle:

... WHERE column LIKE '%{$needle}'
Joshua Powell
źródło
3

pamiętaj, że jest to niebezpieczne:

WHERE `column` LIKE '%{$needle}%'

Ty pierwszy:

$needle = mysql_real_escape_string($needle);

zapobiegnie to możliwym atakom.

Alejandro Moreno
źródło
7
* Niektóre możliwe ataki. Ponadto, mysql_real_escape_stringbędzie przestarzałe w przyszłych wersjach PHP.
Jack Tuck
11
Powinieneś użyć przygotowanych instrukcji i pozostawić ucieczkę do PHP. $stmt = $dbh->prepare("Where 'column' LIKE '{:needle}'"); $stmt->bindParam(':needle', $needle); $stmt->execute();
Cloudworks
3

Prawdopodobnie szukasz find_in_setfunkcji:

Where find_in_set($needle,'column') > 0

Ta funkcja działa jak in_arrayfunkcja w PHP

Andres
źródło