Es ist hilfreich, die folgenden Definitionen zu verstehen:
-
Eine Zeichencodierung Details, wie jedes Symbol binär dargestellt (und daher im Computer gespeichert) wird. Zum Beispiel das Symbol
é
(U+00E9, lateinischer Kleinbuchstabe E mit Akut) ist kodiert als0xc3a9
in UTF-8 (was MySQLutf8
nennt ) und0xe9
in Windows-1252 (was MySQLlatin1
nennt ). -
Ein Zeichensatz ist das Alphabet von Symbolen, die mit einer bestimmten Zeichencodierung dargestellt werden können. Verwirrenderweise wird der Begriff auch gleichbedeutend mit Zeichenkodierung verwendet.
-
Eine Sammlung ist eine Sortierung nach einem Zeichensatz, damit Zeichenketten verglichen werden können. Zum Beispiel:MySQLs
latin1_swedish_ci
collation behandelt die meisten akzentuierten Variationen eines Zeichens als gleichwertig mit dem Basiszeichen, während seinlatin1_general_ci
Die Sortierung ordnet sie vor dem nächsten Basiszeichen an, ist aber nicht äquivalent (es gibt auch andere, bedeutendere Unterschiede:wie die Reihenfolge von Zeichen wieå
,ä
,ö
undß
).
MySQL entscheidet, welche Sortierung auf einen bestimmten Ausdruck angewendet werden soll, wie unter dokumentiert Sortierung von Ausdrücken :Insbesondere hat die Sortierung einer Spalte Vorrang vor der eines String-Literals.
Das WHERE
-Klausel Ihrer Abfrage vergleicht die folgenden Zeichenfolgen:
-
ein Wert in
fos_user.username
, die im Zeichensatz der Spalte (Windows-1252) codiert ist und eine Präferenz für die Sortierunglatin1_swedish_ci
ausdrückt (mit einem Zwangswert von 2); mit -
das String-Literal
'Nrv⧧Kasi'
, kodiert im Zeichensatz der Verbindung (UTF-8, wie von Doctrine konfiguriert) und drückt eine Präferenz für die Sortierungutf8_general_ci
der Verbindung aus (mit einem Zwangswert von 4).
Da der erste dieser Strings einen niedrigeren Koerzitivitätswert hat als der zweite, versucht MySQL, den Vergleich mit der Sortierung dieses Strings durchzuführen:latin1_swedish_ci
. Dazu versucht MySQL, den zweiten String in latin1
umzuwandeln —aber seit dem ⧧
Zeichen in diesem Zeichensatz nicht existiert, schlägt der Vergleich fehl.
Warnung
Man sollte einen Moment innehalten, um zu überlegen, wie die Spalte derzeit codiert ist:Sie versuchen, nach Datensätzen mit fos_user.username
zu filtern ist gleich einer Zeichenkette, die ein Zeichen enthält, das nicht darf in dieser Spalte vorhanden sind !
Wenn Sie glauben, dass die Spalte tut solche Zeichen enthalten, dann haben Sie wahrscheinlich in die Spalte geschrieben, während die Verbindungszeichencodierung auf etwas eingestellt war (z. B. latin1
), was dazu führte, dass MySQL die empfangene Bytefolge als Zeichen interpretierte, die alle im Windows-1252-Zeichensatz enthalten sind.
Wenn dies der Fall ist, sollten Sie Ihre Daten korrigieren, bevor Sie fortfahren!
-
Konvertieren Sie solche Spalten in die Zeichencodierung, die beim Einfügen von Daten verwendet wurde, falls sie von der bestehenden Codierung abweicht:
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
-
Löschen Sie die Codierungsinformationen, die solchen Spalten zugeordnet sind, indem Sie sie in den
binary
konvertieren Zeichensatz:ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
-
ordnen Sie solchen Spalten die Codierung zu, in der Daten tatsächlich übertragen wurden, indem Sie sie in den entsprechenden Zeichensatz konvertieren.
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
Beachten Sie, dass Sie beim Konvertieren von einer Multi-Byte-Codierung möglicherweise die Größe der Spalte erhöhen (oder sogar ihren Typ ändern) müssen, um die maximal mögliche Länge der konvertierten Zeichenfolge aufzunehmen.
Sobald man sicher ist, dass die Spalten korrekt kodiert sind, kann man den Vergleich erzwingen, indem man eine Unicode-Sortierung verwendet, indem man entweder –
-
explizites Konvertieren des Werts
fos_user.username
in einen Unicode-Zeichensatz:WHERE CONVERT(fos_user.username USING utf8) = ?
-
Erzwingen, dass das Zeichenfolgenliteral einen niedrigeren Koerzitivitätswert als die Spalte hat (führt zu einer impliziten Konvertierung des Spaltenwerts in UTF-8):
WHERE fos_user.username = ? COLLATE utf8_general_ci
Oder man könnte, wie Sie sagen, die Spalte(n) dauerhaft in eine Unicode-Codierung konvertieren und ihre Sortierung entsprechend festlegen.
Die Hauptüberlegung ist, dass Unicode-Kodierungen mehr Platz beanspruchen als Einzelbyte-Zeichensätze, also:
-
möglicherweise ist mehr Speicherplatz erforderlich;
-
Vergleiche können langsamer sein; und
-
Index-Präfixlängen müssen möglicherweise angepasst werden (beachten Sie, dass das Maximum in Byte angegeben ist und daher möglicherweise weniger Zeichen als zuvor darstellt).
Beachten Sie auch, wie unter ALTER TABLE
Syntax
: