¿Cómo reparar los errores de "valor de cadena incorrecto"?

162

Después de notar que una aplicación tendía a descartar correos electrónicos aleatorios debido a errores de valor de cadena incorrectos, fui y cambié muchas columnas de texto para usar el utf8conjunto de caracteres de columna y el intercalado de columna predeterminado ( utf8_general_ci) para que los aceptara. Esto solucionó la mayoría de los errores e hizo que la aplicación dejara de recibir errores de sql cuando también llegó a correos electrónicos no latinos.

A pesar de esto, algunos de los correos electrónicos siguen causando errores incorrectos en el valor de la cadena del programa: (Incorrect string value: '\xE4\xC5\xCC\xC9\xD3\xD8...' for column 'contents' at row 1)

La columna de contenido es un MEDIUMTEXTdatatybe que utiliza el utf8conjunto de caracteres de la utf8_general_cicolumna y la clasificación de la columna. No hay banderas que pueda alternar en esta columna.

Teniendo en cuenta que no quiero tocar ni siquiera mirar el código fuente de la aplicación a menos que sea absolutamente necesario:

  • ¿Qué está causando ese error? (sí, sé que los correos electrónicos están llenos de basura aleatoria, pero pensé que utf8 sería bastante permisivo)
  • ¿Cómo puedo arreglarlo?
  • ¿Cuáles son los efectos probables de tal solución?

Una cosa que consideré fue cambiar a un utf8 varchar ([algún número grande]) con la bandera binaria activada, pero no estoy familiarizado con MySQL, y no tengo idea si esa solución tiene sentido.

Brian
fuente
3
Post-mortem: la solución de RichieHindle resolvió el problema y no introdujo ningún problema adicional en el momento en que se estaba ejecutando. Puede que haya sido un truco, pero funcionó y me permitió evitar ensuciarme las manos con un software de terceros que no entiendo completamente. En este punto, hemos actualizado a una versión más nueva del software / esquema que maneja todos estos problemas de codificación correctamente (y es lo suficientemente nuevo como para que sea realmente compatible), haciendo innecesario el hack.
Brian

Respuestas:

43

"\xE4\xC5\xCC\xC9\xD3\xD8"no es válido UTF-8. Probado con Python:

>>> "\xE4\xC5\xCC\xC9\xD3\xD8".decode("utf-8")
...
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 0-2: invalid data

Si está buscando una manera de evitar errores de decodificación dentro de la base de datos, la codificación cp1252 (también conocida como "Windows-1252", también conocida como "Windows Western European") es la codificación más permisiva que existe: cada valor de byte es un punto de código válido.

Por supuesto, ya no va a entender UTF-8 genuino, ni ninguna otra codificación que no sea cp1252, pero parece que no le preocupa demasiado.

RichieHindle
fuente
44
¿Qué quiere decir exactamente con "Por supuesto que ya no va a entender el UTF-8 genuino"?
Brian
55
@Brian: Si le dices que le estás dando cp1252, y en realidad le das el UTF-8 porque, por ejemplo, caféva a malinterpretar eso comocafé . No se bloqueará, pero no comprenderá los caracteres de bits altos.
RichieHindle
3
@Richie: La base de datos puede llamar felizmente a los datos lo que quiera, pero si el código php que lo agarra lo está metiendo en una cadena, eso no hará mucha diferencia ... ¿lo hará? No veo exactamente dónde la falta de comprensión de UTF-8 está teniendo un impacto.
Brian
77
@Brian: No, tienes razón. El momento en que marcaría la diferencia sería dentro de la base de datos, por ejemplo, si usó una cláusula ORDER BY en su SQL, la clasificación sería inestable cuando tuviera caracteres no ASCII.
RichieHindle
11
Desmarca esta respuesta como la solución, ocultar un error no es la solución de nada. Retire la lámpara de sobrecalentamiento de su automóvil y verá.
David Vartanian
133

No sugeriría que Richies respondiera, porque estás arruinando los datos dentro de la base de datos. No solucionaría su problema, sino que trataría de "ocultarlo" y no podría realizar operaciones esenciales de la base de datos con los datos dañados.

Si encuentra este error, los datos que está enviando no están codificados en UTF-8 o su conexión no está en UTF-8. Primero, verifique que la fuente de datos (un archivo, ...) realmente sea ​​UTF-8.

Luego, verifique la conexión de su base de datos, debe hacer esto después de conectarse:

SET NAMES 'utf8';
SET CHARACTER SET utf8;

A continuación, verifique que las tablas donde se almacenan los datos tengan el conjunto de caracteres utf8:

SELECT
  `tables`.`TABLE_NAME`,
  `collations`.`character_set_name`
FROM
  `information_schema`.`TABLES` AS `tables`,
  `information_schema`.`COLLATION_CHARACTER_SET_APPLICABILITY` AS `collations`
WHERE
  `tables`.`table_schema` = DATABASE()
  AND `collations`.`collation_name` = `tables`.`table_collation`
;

Por último, verifique la configuración de su base de datos:

mysql> show variables like '%colla%';
mysql> show variables like '%charac%';

Si el origen, el transporte y el destino son UTF-8, su problema se ha ido;)

nico gawenda
fuente
1
@Kariem: Esto es extraño, porque esta configuración está cubierta por el comando SET NAMES, que es equivalente a llamar a SET character_set_client, SET character_set_results, SET character_set_connection dev.mysql.com/doc/refman/5.1/en/charset-connection.html
nico gawenda
2
El segundo comando debería ser SET CHARACTER SET utf8(no CHARACTER_SET)
Codificador
66
Si bien esta respuesta ayuda a investigar el problema, no responde qué hacer para solucionarlo. Veo "latin1" en lugar de "utf-8".
Vanuan
2
esta respuesta es excelente para explicar el problema pero muy pobre para detallar la solución (que es lo que solicitó OP). @nicogawenda: ¿Cuáles son todas las consultas SQL que se ejecutarán para solucionar completamente el problema? ¿Cómo arreglar todos los datos preexistentes?
Clint Eastwood el
1
"Si la fuente, el transporte y el destino son UTF-8, su problema se ha ido;)", ese fue el truco para mí
suarsenegger
80

Los tipos utf-8 de MySQL no son realmente utf-8: solo usa hasta tres bytes por carácter y solo admite el plano multilingüe básico (es decir, sin Emoji, sin plano astral, etc.).

Si necesita almacenar valores de planos Unicode superiores, necesita las codificaciones utf8mb4 .

moeffju
fuente
9
Creo que esta es probablemente la mejor solución. Actualice a 5.5 y reemplace utf8 con utf8mb4 en las respuestas anteriores. Estaba insertando datos utf8 de Twitter que tenían emojis u otros caracteres que necesitaban 4 bytes.
rmarscher
Supongamos que no vamos a actualizar a 5.5. ¿Cómo suprimimos los errores?
Usuario
Me desplacé demasiado lejos para obtener esta respuesta más útil
handheldblender
1
10 años desde la pregunta original. Que se sepa que la codificación utf8 de MySQL no es adecuada utf8. Use utf8mb4! Lo mismo va para MariaDB. De lo contrario no puedes tener lágrimas de alegría 😂
Liam
51

La tabla y los campos tienen la codificación incorrecta; sin embargo, puede convertirlos a UTF-8.

ALTER TABLE logtest CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE logtest DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

ALTER TABLE logtest CHANGE title title VARCHAR(100) CHARACTER SET utf8 COLLATE utf8_general_ci;
Jiayu Wang
fuente
1
Creo que esta es la respuesta correcta de todas. Tengo dos tablas que tienen un formato varchar utf8 cada una. uno de ellos recibió el error, el otro está bien. incluso si el usuario 'update select' hace una copia de la columna 'buena' utf8 a otra tabla, se produce el mismo error. Es porque las dos tablas se crean en diferentes versiones de MySQL.
AiShiguang
¡Si! También fue una configuración incorrecta de mi tabla de base de datos. Creo que esta respuesta debería ser la correcta. Mi problema fue que la clasificación seleccionada era utf8_unicode_ci en lugar de utf8_general_ci. Gracias :)
jprivillaso
2
¿Qué está haciendo esta respuesta aquí abajo? Debería estar en la cima
Sagun Shrestha, el
1
este ayuda, te dice qué probar, en lugar de lo que puede estar mal.
Victor Di
¡Gracias! Simplemente me ayudó mucho, había cambiado la tabla de colación y pensé que debería ser así, pero los campos seguían siendo una colación ascii ...
Radu
25

Resolví este problema hoy alterando la columna al tipo 'LONGBLOB' que almacena bytes sin procesar en lugar de caracteres UTF-8.

La única desventaja de hacer esto es que debes ocuparte de la codificación tú mismo. Si un cliente de su aplicación usa codificación UTF-8 y otro usa CP1252, es posible que sus correos electrónicos se envíen con caracteres incorrectos. Para evitar esto, use siempre la misma codificación (por ejemplo, UTF-8) en todas sus aplicaciones .

Consulte esta página http://dev.mysql.com/doc/refman/5.0/en/blob.html para obtener más detalles sobre las diferencias entre TEXT / LONGTEXT y BLOB / LONGBLOB. También hay muchos otros argumentos en la web que discuten estos dos.

frankshaka
fuente
1
Esta solución parece el camino más fácil. Probé algunas otras codificaciones sin éxito.
Simeon Abolarinwa
10

Primero verifique si su default_character_set_name es utf8.

SELECT default_character_set_name FROM information_schema.SCHEMATA S WHERE schema_name = "DBNAME";

Si el resultado no es utf8, debe convertir su base de datos. Al principio debes guardar un vertedero.

Para cambiar la codificación del juego de caracteres a UTF-8 para todas las tablas en la base de datos especificada, escriba el siguiente comando en la línea de comandos. Reemplace DBNAME con el nombre de la base de datos:

mysql --database=DBNAME -B -N -e "SHOW TABLES" | awk '{print "SET foreign_key_checks = 0; ALTER TABLE", $1, "CONVERT TO CHARACTER SET utf8 COLLATE utf8_general_ci; SET foreign_key_checks = 1; "}' | mysql --database=DBNAME

Para cambiar la codificación del juego de caracteres a UTF-8 para la base de datos, escriba el siguiente comando en el indicador mysql >. Reemplace DBNAME con el nombre de la base de datos:

ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;

Ahora puede volver a intentar escribir el carácter utf8 en su base de datos. Esta solución me ayuda cuando intento cargar 200000 filas de archivos csv en mi base de datos.

Babacar Gningue
fuente
8

En general, esto sucede cuando inserta cadenas en columnas con codificación / intercalación incompatible.

Obtuve este error cuando tuve DISPARADORES, que heredan la intercalación del servidor por alguna razón. Y el valor predeterminado de mysql es (al menos en Ubuntu) latin-1 con clasificación sueca. Aunque tenía una base de datos y todas las tablas configuradas en UTF-8, todavía tenía que configurarmy.cnf :

/etc/mysql/my.cnf:

[mysqld]
character-set-server=utf8
default-character-set=utf8

Y esto debe enumerar todos los desencadenantes con utf8- *:

select TRIGGER_SCHEMA, TRIGGER_NAME, CHARACTER_SET_CLIENT, COLLATION_CONNECTION, DATABASE_COLLATION from information_schema.TRIGGERS

Y algunas de las variables enumeradas por esto también deben tener utf-8- * (sin latin-1 u otra codificación):

show variables like 'char%';
Ondra Žižka
fuente
6

Aunque su intercalación está establecida en utf8_general_ci, sospecho que la codificación de caracteres de la base de datos, la tabla o incluso la columna puede ser diferente.

ALTER TABLE tabale_name MODIFY COLUMN column_name VARCHAR(255)  
CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL;
Sameera Prasad Jayasinghe
fuente
5

Recibí un error similar ( Incorrect string value: '\xD0\xBE\xDO\xB2. ...' for 'content' at row 1). Intenté cambiar el conjunto de caracteres de la columna utf8mb4y, después de eso, el error cambió a 'Data too long for column 'content' at row 1'.
Resultó que mysql me muestra un error incorrecto. Volví el conjunto de caracteres de la columna a utf8y cambié el tipo de columna a MEDIUMTEXT. Después de eso, el error desapareció.
Espero que esto ayude a alguien.
Por cierto, MariaDB en el mismo caso (he probado el mismo INSERTAR allí) simplemente cortó un texto sin error.

AVKurov
fuente
MySQL también cansé tantas cosas, me di cuenta de que mysql no admite la codificación utf-8 de 4 bytes en esta versión y estaba muriendo tratando de entender qué está causando esto. Cambiar el tipo aparentemente fue la respuesta, una solución inmediata.
Liza
4

Ese error significa que tiene la cadena con codificación incorrecta (por ejemplo, está tratando de ingresar la cadena codificada ISO-8859-1 en la columna codificada UTF-8), o la columna no admite los datos que está tratando de ingresar.

En la práctica, el último problema es causado por la implementación de MySQL UTF-8 que solo admite caracteres UNICODE que necesitan 1-3 bytes cuando se representan en UTF-8. Consulte "Valor de cadena incorrecto" al intentar insertar UTF-8 en MySQL a través de JDBC. para detalles.

Mikko Rantalainen
fuente
2

La solución para mí cuando me encuentro con este valor de cadena incorrecto: '\ xF8' para el error de columna usando scriptcase fue asegurarme de que mi base de datos esté configurada para utf8 general ci y también lo son mis intercalaciones de campo. Luego, cuando hago la importación de datos de un archivo csv, cargo el csv en UE Studio y luego lo guardo formateado como utf8 y ¡Voila! Funciona de maravilla, 29000 registros allí sin errores. Anteriormente estaba tratando de importar un csv creado por Excel.

mainebrain
fuente
2

He probado todas las soluciones anteriores (que aportan puntos válidos), pero nada funcionaba para mí.

Hasta que descubrí que mis asignaciones de campo de tabla MySQL en C # usaban un tipo incorrecto: MySqlDbType.Blob . Lo cambié a MySqlDbType.Text y ahora puedo escribir todos los símbolos UTF8 que quiero!

ps Mi campo de tabla MySQL es del tipo "Texto largo". Sin embargo, cuando autogeneré las asignaciones de campo usando el software MyGeneration, configuró automáticamente el tipo de campo como MySqlDbType.Blob en C #.

Curiosamente, he estado usando el tipo MySqlDbType.Blob con caracteres UTF8 durante muchos meses sin problemas, hasta que un día intenté escribir una cadena con algunos caracteres específicos.

Espero que esto ayude a alguien que está luchando por encontrar una razón para el error.

Ugnius Ramanauskas
fuente
1

Agregué el binario antes del nombre de la columna y resolví el error del juego de caracteres.

insertar en los valores de la tabla A (binary stringcolname1);

Richardhe2007
fuente
1

Hola, también recibí este error cuando uso mis bases de datos en línea del servidor godaddy, creo que tiene la versión mysql de 5.1 o más. pero cuando lo hago desde mi servidor localhost (versión 5.7) estaba bien después de eso, creé la tabla desde el servidor local y la copié en el servidor en línea usando mysql yog, creo que el problema está en el juego de caracteres

Captura de pantalla aquí

Hashain Lakshan
fuente
1

Para solucionar este error, actualicé mi base de datos MySQL a utf8mb4 que admite el conjunto completo de caracteres Unicode siguiendo este tutorial detallado . Sugiero que lo revise con cuidado, porque hay bastantes problemas (por ejemplo, las claves de índice pueden ser demasiado grandes debido a las nuevas codificaciones después de las cuales debe modificar los tipos de campo).

metakermit
fuente
1

Hay buenas respuestas aquí. Solo estoy agregando el mío ya que me encontré con el mismo error, pero resultó ser un problema completamente diferente. (Tal vez en la superficie lo mismo, pero una causa raíz diferente).

Para mí, el error ocurrió para el siguiente campo:

@Column(nullable = false, columnDefinition = "VARCHAR(255)")
private URI consulUri;

Esto termina siendo almacenado en la base de datos como una serialización binaria de la URIclase. Esto no levantó ninguna señal con las pruebas unitarias (usando H2) o las pruebas de integración / CI (usando MariaDB4j ), explotó en nuestra configuración similar a la producción. (Aunque, una vez que se entendió el problema, fue bastante fácil ver el valor incorrecto en la instancia de MariaDB4j; simplemente no explotó la prueba). La solución fue construir un mapeador de tipos personalizado:

package redacted;

import javax.persistence.AttributeConverter;
import java.net.URI;
import java.net.URISyntaxException;

import static java.lang.String.format;

public class UriConverter implements AttributeConverter<URI, String> {
    @Override
    public String convertToDatabaseColumn(URI attribute) {
        return attribute.toString();
    }

    @Override
    public URI convertToEntityAttribute(String field) {
        try {
            return new URI(field);
        }
        catch (URISyntaxException e) {
            throw new RuntimeException(format("could not convert database field to URI: %s", field));
        }
    }
}

Usado de la siguiente manera:

@Column(nullable = false, columnDefinition = "VARCHAR(255)")
@Convert(converter = UriConverter.class)
private URI consulUri;

En lo que respecta a Hibernate, parece que tiene un montón de mapeadores de tipos proporcionados , incluidos para java.net.URL, pero no para java.net.URI(que es lo que necesitábamos aquí).

Sander Verhagen
fuente
1

En mi caso, ese problema se resolvió cambiando la codificación de la columna Mysql a 'binario' (el tipo de datos se cambiará automáticamente a VARBINARIO). Probablemente no pueda filtrar o buscar con esa columna, pero no necesito eso.

WilyDen
fuente
1

Si procesa el valor con alguna función de cadena antes de guardar, asegúrese de que la función pueda manejar correctamente caracteres multibyte. Las funciones de cadena que no pueden hacer eso y, por ejemplo, intentan truncar, podrían dividir uno de los caracteres multibyte en el medio, y eso puede causar tales situaciones de error de cadena.

En PHP, por ejemplo, necesitaría cambiar de substra mb_substr.

WoodrowShigeru
fuente
0

En mi caso, primero me encuentro con un '???' en mi sitio web, luego verifico el juego de caracteres de Mysql que ahora es latino, así que lo cambio a utf-8, luego reinicio mi proyecto, luego recibí el mismo error, luego descubrí que me olvidé de cambiar el juego de caracteres de la base de datos y cambiar a utf-8, boom, funcionó.

acoder2013
fuente
0

Intenté casi todos los pasos mencionados aquí. Ninguno funcionó. Descargado mariadb. Funcionó. Sé que esto no es una solución, pero esto podría ayudar a alguien a identificar el problema rápidamente o dar una solución temporal.

Server version: 10.2.10-MariaDB - MariaDB Server
Protocol version: 10
Server charset: UTF-8 Unicode (utf8)
cherankrish
fuente
0

En mi caso, Incorrect string value: '\xCC\x88'...el problema era que una o-diéresis estaba en estado descompuesto. Esta pregunta y respuesta me ayudó a comprender la diferencia entre y ö. En PHP, la solución para mí fue usar la biblioteca Normalizer de PHP . Ej Normalizer::normalize('o¨', Normalizer::FORM_C).

MM.
fuente
-2

1 - Debe declarar en su conexión la propiedad de encontrar UTF8. http://php.net/manual/en/mysqli.set-charset.php .

2 - Si está usando la línea de comando mysql para ejecutar un script, debe usar la bandera, como: Cmd: C:\wamp64\bin\mysql\mysql5.7.14\bin\mysql.exe -h localhost -u root -P 3306 --default-character-set=utf8 omega_empresa_parametros_336 < C:\wamp64\www\PontoEletronico\PE10002Corporacao\BancoDeDadosModelo\omega_empresa_parametros.sql

Roger Gusmao
fuente