Es útil entender las siguientes definiciones:
-
Una codificación de caracteres detalla cómo se representa cada símbolo en binario (y por lo tanto se almacena en la computadora). Por ejemplo, el símbolo
é
(U+00E9, letra E minúscula latina con agudo) está codificado como0xc3a9
en UTF-8 (que MySQL llamautf8
) y0xe9
en Windows-1252 (que MySQL llamalatin1
). -
Un conjunto de caracteres es el alfabeto de símbolos que se pueden representar usando una codificación de caracteres dada. De manera confusa, el término también se usa para significar lo mismo que la codificación de caracteres.
-
Una colección es una ordenación en un conjunto de caracteres, de modo que las cadenas se pueden comparar. Por ejemplo:
latin1_swedish_ci
de MySQL la intercalación trata la mayoría de las variaciones acentuadas de un carácter como equivalente al carácter base, mientras que sulatin1_general_ci
la intercalación los ordenará antes del siguiente carácter base pero no equivalente (también hay otras diferencias más significativas:como el orden de los caracteres comoå
,ä
,ö
yß
).
MySQL decidirá qué intercalación se debe aplicar a una expresión dada como se documenta en Recopilación de expresiones :en particular, la intercalación de una columna tiene prioridad sobre la de un literal de cadena.
El WHERE
cláusula de su consulta compara las siguientes cadenas:
-
un valor en
fos_user.username
, codificado en el conjunto de caracteres de la columna (Windows-1252) y expresando una preferencia por su intercalaciónlatin1_swedish_ci
(con un valor de coercibilidad de 2); con -
el literal de cadena
'Nrv⧧Kasi'
, codificado en el conjunto de caracteres de la conexión (UTF-8, según lo configurado por Doctrine) y expresando una preferencia por la intercalación de la conexiónutf8_general_ci
(con un valor de coercibilidad de 4).
Dado que la primera de estas cadenas tiene un valor de coercibilidad más bajo que la segunda, MySQL intenta realizar la comparación utilizando la intercalación de esa cadena:latin1_swedish_ci
. Para hacerlo, MySQL intenta convertir la segunda cadena a latin1
—pero desde el ⧧
carácter no existe en ese conjunto de caracteres, la comparación falla.
Advertencia
Uno debe hacer una pausa por un momento para considerar cómo está codificada actualmente la columna:está intentando filtrar registros donde fos_user.username
es igual a una cadena que contiene un carácter que no puede existe en esa columna !
Si cree que la columna sí contiene dichos caracteres, entonces probablemente escribió en la columna mientras la codificación de caracteres de conexión estaba configurada en algo (por ejemplo, latin1
) que hizo que MySQL interpretara la secuencia de bytes recibida como caracteres que están todos en el conjunto de caracteres de Windows-1252.
Si este es el caso, antes de continuar, ¡debería corregir sus datos!
-
convierta dichas columnas a la codificación de caracteres que se usó en la inserción de datos, si es diferente a la codificación actual:
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET foo;
-
elimine la información de codificación asociada con tales columnas convirtiéndolas al
binary
juego de caracteres:ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET binary;
-
asocie con dichas columnas la codificación en la que los datos se transmitieron realmente convirtiéndolos al conjunto de caracteres relevante.
ALTER TABLE fos_users MODIFY username VARCHAR(123) CHARACTER SET bar;
Tenga en cuenta que, si realiza la conversión desde una codificación de varios bytes, es posible que deba aumentar el tamaño de la columna (o incluso cambiar su tipo) para acomodar la longitud máxima posible de la cadena convertida.
Una vez que uno está seguro de que las columnas están codificadas correctamente, se puede forzar la realización de la comparación mediante una intercalación Unicode mediante:
-
convirtiendo explícitamente el valor
fos_user.username
a un juego de caracteres Unicode:WHERE CONVERT(fos_user.username USING utf8) = ?
-
obligar al literal de cadena a tener un valor de coercibilidad más bajo que la columna (provocará una conversión implícita del valor de la columna a UTF-8):
WHERE fos_user.username = ? COLLATE utf8_general_ci
O uno podría, como usted dice, convertir permanentemente la(s) columna(s) a una codificación Unicode y establecer su intercalación apropiadamente.
La consideración principal es que las codificaciones Unicode ocupan más espacio que los conjuntos de caracteres de un solo byte, por lo que:
-
es posible que se requiera más espacio de almacenamiento;
-
las comparaciones pueden ser más lentas; y
-
Es posible que sea necesario ajustar la longitud del prefijo de índice (tenga en cuenta que el máximo está en bytes, por lo que puede representar menos caracteres que antes).
Además, tenga en cuenta que, como se documenta en ALTER TABLE
Sintaxis
: