Różni operatorzy
LIKE
i =
są różnymi operatorami. Większość odpowiedzi tutaj koncentruje się na obsłudze symboli wieloznacznych, co nie jest jedyną różnicą między tymi operatorami!
=
to operator porównania, który działa na liczbach i ciągach. Podczas porównywania ciągów operator porównania porównuje całe ciągi .
LIKE
jest operatorem łańcuchowym, który porównuje znak po znaku .
Aby skomplikować sprawę, obaj operatorzy stosują sortowanie, które może mieć istotny wpływ na wynik porównania.
Motywujący przykład
Najpierw zidentyfikujmy przykład, w którym operatorzy ci uzyskują oczywiście różne wyniki. Pozwól mi zacytować z podręcznika MySQL:
Zgodnie ze standardem SQL LIKE wykonuje dopasowanie dla poszczególnych znaków, dzięki czemu może generować wyniki inne niż operator =:
mysql> SELECT 'ä' LIKE 'ae' COLLATE latin1_german2_ci;
+-----------------------------------------+
| 'ä' LIKE 'ae' COLLATE latin1_german2_ci |
+-----------------------------------------+
| 0 |
+-----------------------------------------+
mysql> SELECT 'ä' = 'ae' COLLATE latin1_german2_ci;
+--------------------------------------+
| 'ä' = 'ae' COLLATE latin1_german2_ci |
+--------------------------------------+
| 1 |
+--------------------------------------+
Należy pamiętać, że ta strona podręcznika MySQL nazywa funkcji porównawczych String , a =
nie jest omawiana, co oznacza, że =
nie jest to ściśle funkcją porównania ciągów.
W jaki sposób =
działa?
SQL Standardowe § 8.2 opisuje sposób =
porównuje ciągi:
Porównanie dwóch ciągów znaków określa się w następujący sposób:
a) Jeśli długość w znakach X nie jest równa długości w znakach Y, wówczas dla celów porównania efektywnie krótszy ciąg zostaje zastąpiony kopią samego siebie, która została przedłużona do długości dłuższego ciągu przez konkatenację po prawej stronie jednego lub więcej znaków padu, gdzie znak padu jest wybierany na podstawie CS. Jeśli CS ma atrybut NO PAD, to znak pad jest znakiem zależnym od implementacji innym niż dowolny znak w zestawie znaków X i Y, który zestawia mniej niż dowolny ciąg znaków w CS. W przeciwnym razie znak padu to.
b) Wynik porównania X i Y jest podany przez kolejność zestawiania CS.
c) W zależności od sekwencji zestawiania dwa ciągi znaków mogą się równać, nawet jeśli mają różną długość lub zawierają różne ciągi znaków. Gdy operacje MAX, MIN, DISTINCT, odniesienia do kolumny grupującej oraz operatory UNION, EXCEPT i INTERSECT odnoszą się do ciągów znaków, konkretna wartość wybrana przez te operacje z zestawu takich równych wartości zależy od implementacji.
(Podkreślenie dodane.)
Co to znaczy? Oznacza to, że podczas porównywania ciągów =
operator jest tylko cienkim owinięciem wokół bieżącego sortowania. Zestawienie to biblioteka, która ma różne reguły porównywania ciągów. Oto przykład sortowania binarnego z MySQL :
static int my_strnncoll_binary(const CHARSET_INFO *cs __attribute__((unused)),
const uchar *s, size_t slen,
const uchar *t, size_t tlen,
my_bool t_is_prefix)
{
size_t len= MY_MIN(slen,tlen);
int cmp= memcmp(s,t,len);
return cmp ? cmp : (int)((t_is_prefix ? len : slen) - tlen);
}
To konkretne zestawienie zdarza się porównywać bajt po bajcie (dlatego nazywa się to „binarne” - nie nadaje żadnego specjalnego znaczenia ciągom znaków). Inne zestawienia mogą zapewniać bardziej zaawansowane porównania.
Na przykład tutaj jest zestawienie UTF-8, które obsługuje porównania bez rozróżniania wielkości liter. Kod jest za długi, aby go wkleić, ale przejdź do tego linku i przeczytaj treść my_strnncollsp_utf8mb4()
. To zestawianie może przetwarzać wiele bajtów jednocześnie i może stosować różne transformacje (takie jak porównanie bez rozróżniania wielkości liter). =
Operator jest całkowicie oderwana od napotkane pęczka.
W jaki sposób LIKE
działa?
SQL Standardowe § 8.5 opisuje sposób LIKE
porównuje ciągi:
<predicate>
M LIKE P
jest prawdą, jeśli istnieje podział M na podciągi, tak aby:
i) Podciąg M jest sekwencją 0 lub więcej ciągłych <reprezentacji znaków> M, a każda <reprezentacja znaków> M jest częścią dokładnie jednego podłańcucha.
ii) Jeśli i-ty specyfikator podciągu P jest dowolnym specyfikatorem znaków, i -ty podciąg M jest dowolną <reprezentacją znaków>.
iii) Jeśli i-ty specyfikator podciągu P jest arbitralnym specyfikatorem ciągu, to i-ty podciąg M jest dowolną sekwencją 0 lub więcej <reprezentacji znaków>.
iv) Jeśli i-ty specyfikator podciągu P nie jest ani arbitralnym specyfikatorem znaku, ani arbitralnym specyfikatorem łańcucha, to i-ty podciąg M jest równy temu specyfikatorowi podłańcuchu zgodnie z sekwencją zestawiania <podobnego predykatu>, bez dodanie znaków <spacja> do M i ma taką samą długość jak ten specyfikator podłańcucha.
v) Liczba podciągów M jest równa liczbie specyfikatorów podciągów P.
(Podkreślenie dodane.)
To dość trudne, więc załamajmy się. Pozycje ii i iii odnoszą się odpowiednio do symboli wieloznacznych _
i %
. Jeśli P
nie zawiera żadnych symboli wieloznacznych, obowiązuje tylko pozycja iv. Jest to przypadek zainteresowania PO.
W tym przypadku porównuje każdy „podłańcuch” (poszczególne znaki) M
z każdym podciągiem przy P
użyciu bieżącego sortowania.
Wnioski
Najważniejsze jest to, że porównując ciągi, =
porównuje cały ciąg, jednocześnie LIKE
porównując jeden znak na raz. Oba porównania wykorzystują bieżące zestawienie. Różnica ta prowadzi do różnych wyników w niektórych przypadkach, o czym świadczy pierwszy przykład w tym poście.
Którego powinieneś użyć? Nikt nie może ci tego powiedzieć - musisz użyć tego, który jest odpowiedni dla twojego przypadku użycia. Nie przedwcześnie optymalizuj, przełączając operatory porównania.