Je užitečné porozumět následujícím definicím:
-
Kódování znaků podrobně popisuje, jak je každý symbol reprezentován binárně (a tedy uložen v počítači). Například symbol
é
(U+00E9, latinské malé písmeno E s akutním) je kódováno jako0xc3a9
v UTF-8 (které MySQL nazýváutf8
) a0xe9
v Windows-1252 (které MySQL nazýválatin1
). -
sadu znaků je abeceda symbolů, které lze znázornit pomocí daného kódování znaků. Je matoucí, že tento termín je také používán ve významu stejně jako kódování znaků.
-
Posouzení je řazení na znakové sadě, takže řetězce lze porovnávat. Například:
latin1_swedish_ci
MySQL Collation považuje většinu variací znaku s diakritikou za ekvivalent k základnímu znaku, zatímco jeholatin1_general_ci
řazení je seřadí před dalším základním znakem, ale ne ekvivalentní (existují i další, významnější rozdíly:například pořadí znaků jakoå
,ä
,ö
aß
).
MySQL rozhodne, které řazení se má použít na daný výraz, jak je zdokumentováno v Porovnání výrazů :konkrétně řazení sloupce má přednost před řetězcovým literálem.
WHERE
klauzule vašeho dotazu porovnává následující řetězce:
-
hodnotu v
fos_user.username
, zakódovaný ve znakové sadě sloupce (Windows-1252) a vyjadřující preference pro jeho řazenílatin1_swedish_ci
(s hodnotou koercibility 2); s -
řetězcový literál
'Nrv⧧Kasi'
, zakódované ve znakové sadě připojení (UTF-8, jak je nakonfigurováno Doctrine) a vyjadřující preferenci pro řazení připojeníutf8_general_ci
(s hodnotou koercibility 4).
Vzhledem k tomu, že první z těchto řetězců má nižší hodnotu koercibility než druhý, MySQL se pokusí provést porovnání pomocí řazení tohoto řetězce:latin1_swedish_ci
. Za tímto účelem se MySQL pokusí převést druhý řetězec na latin1
—ale protože ⧧
znak v této znakové sadě neexistuje, porovnání se nezdaří.
Upozornění
Měli bychom se na chvíli zastavit a zvážit, jak je sloupec aktuálně kódován:pokoušíte se filtrovat záznamy, kde fos_user.username
se rovná řetězci, který obsahuje znak, který nemůže existují v tomto sloupci !
Pokud se domníváte, že sloupec ano obsahovat takové znaky, pak jste pravděpodobně psali do sloupce, když bylo kódování znaků připojení na něco nastaveno (např. latin1
), což způsobilo, že MySQL interpretuje přijatou sekvenci bajtů jako znaky, které jsou všechny ve znakové sadě Windows-1252.
V takovém případě byste měli před dalším pokračováním opravit svá data!
-
převeďte takové sloupce na kódování znaků, které bylo použito při vkládání dat, pokud se liší od stávajícího kódování:
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
-
zahoďte informace o kódování spojené s takovými sloupci jejich převedením na
binary
znaková sada:ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
-
přiřadit k takovým sloupcům kódování, ve kterém byla data skutečně přenášena, jejich převodem na příslušnou znakovou sadu.
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
Všimněte si, že při převodu z vícebajtového kódování může být nutné zvětšit velikost sloupce (nebo dokonce změnit jeho typ), aby se přizpůsobila maximální možné délce převedeného řetězce.
Jakmile se ujistíte, že jsou sloupce správně zakódovány, můžete vynutit provedení porovnání pomocí řazení Unicode buď –
-
explicitně převede hodnotu
fos_user.username
na znakovou sadu Unicode:WHERE CONVERT(fos_user.username USING utf8) = ?
-
vynucení, aby měl řetězcový literál nižší hodnotu koercibility než sloupec (způsobí implicitní převod hodnoty sloupce na UTF-8):
WHERE fos_user.username = ? COLLATE utf8_general_ci
Nebo by se dalo, jak říkáte, trvale převést sloupec(y) do kódování Unicode a vhodně nastavit jeho řazení.
Principem je, že kódování Unicode zabírá více místa než jednobajtové znakové sady, takže:
-
může být vyžadováno více úložiště;
-
srovnávání může být pomalejší; a
-
Délky předpon indexu může být nutné upravit (všimněte si, že maximum je v bajtech, takže může představovat méně znaků než dříve).
Mějte také na paměti, že jak je zdokumentováno v části ALTER TABLE
Syntaxe
: