È utile comprendere le seguenti definizioni:
-
Una codifica dei caratteri dettagli come ogni simbolo è rappresentato in binario (e quindi memorizzato nel computer). Ad esempio, il simbolo
é
(U+00E9, minuscola latina E con acuto) è codificato come0xc3a9
in UTF-8 (che MySQL chiamautf8
) e0xe9
in Windows-1252 (che MySQL chiamalatin1
). -
Un insieme di caratteri è l'alfabeto dei simboli che possono essere rappresentati utilizzando una determinata codifica dei caratteri. In modo confuso, il termine è anche usato per indicare la stessa codifica dei caratteri.
-
Una collazione è un ordinamento su un set di caratteri, in modo che le stringhe possano essere confrontate. Ad esempio:
latin1_swedish_ci
di MySQL collation tratta la maggior parte delle variazioni accentate di un carattere come equivalenti al carattere di base, mentre il suolatin1_general_ci
collation li ordinerà prima del carattere di base successivo ma non equivalenti (ci sono anche altre differenze più significative:come l'ordine di caratteri comeå
,ä
,ö
eß
).
MySQL deciderà quale confronto applicare a una determinata espressione, come documentato in Fascicolazione di espressioni :in particolare, la collation di una colonna ha la precedenza su quella di una stringa letterale.
Il WHERE
clausola della tua query confronta le seguenti stringhe:
-
un valore in
fos_user.username
, codificato nel set di caratteri della colonna (Windows-1252) ed esprimendo una preferenza per le regole di confrontolatin1_swedish_ci
(con valore di coercibilità 2); con -
la stringa letterale
'Nrv⧧Kasi'
, codificato nel set di caratteri della connessione (UTF-8, come configurato da Doctrine) ed esprimendo una preferenza per le regole di confronto della connessioneutf8_general_ci
(con un valore di coercibilità di 4).
Poiché la prima di queste stringhe ha un valore di coercibilità inferiore rispetto alla seconda, MySQL tenta di eseguire il confronto utilizzando le regole di confronto di quella stringa:latin1_swedish_ci
. Per farlo, MySQL tenta di convertire la seconda stringa in latin1
—ma dal ⧧
carattere non esiste in quel set di caratteri, il confronto non riesce.
Avviso
Ci si dovrebbe fermare un momento per considerare come è attualmente codificata la colonna:stai tentando di filtrare i record in cui fos_user.username
è uguale a una stringa che contiene un carattere che non può esistono in quella colonna !
Se ritieni che la colonna fa contengono tali caratteri, quindi probabilmente hai scritto nella colonna mentre la codifica dei caratteri di connessione era impostata su qualcosa (ad es. latin1
) che ha indotto MySQL a interpretare la sequenza di byte ricevuta come caratteri che sono tutti nel set di caratteri di Windows-1252.
Se questo è il caso, prima di continuare dovresti correggere i tuoi dati!
-
convertire tali colonne nella codifica dei caratteri utilizzata per l'inserimento dei dati, se diversa dalla codifica incumbent:
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
-
elimina le informazioni di codifica associate a tali colonne convertendole nel
binary
set di caratteri:ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
-
associare a tali colonne la codifica in cui i dati sono stati effettivamente trasmessi convertendoli nel relativo set di caratteri.
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
Si noti che, se si esegue la conversione da una codifica multi-byte, potrebbe essere necessario aumentare la dimensione della colonna (o addirittura cambiarne il tipo) per accogliere la lunghezza massima possibile della stringa convertita.
Una volta che si è certi che le colonne siano codificate correttamente, è possibile forzare l'esecuzione del confronto utilizzando un confronto Unicode in uno dei due modi:
-
convertendo esplicitamente il valore
fos_user.username
in un set di caratteri Unicode:WHERE CONVERT(fos_user.username USING utf8) = ?
-
forzare la stringa letterale ad avere un valore di coercibilità inferiore rispetto alla colonna (causa una conversione implicita del valore della colonna in UTF-8):
WHERE fos_user.username = ? COLLATE utf8_general_ci
Oppure si potrebbe, come dici tu, convertire permanentemente le colonne in una codifica Unicode e impostarne le regole di confronto in modo appropriato.
La considerazione principale è che le codifiche Unicode occupano più spazio rispetto ai set di caratteri a byte singolo, quindi:
-
potrebbe essere necessario più spazio di archiviazione;
-
i confronti possono essere più lenti; e
-
potrebbe essere necessario regolare la lunghezza del prefisso dell'indice (nota che il massimo è in byte, quindi potrebbe rappresentare un numero di caratteri inferiore rispetto a prima).
Inoltre, tieni presente che, come documentato in ALTER TABLE
Sintassi
: