Comment corriger les erreurs de «valeur de chaîne incorrecte»?

162

Après avoir remarqué qu'une application avait tendance à rejeter les e-mails aléatoires en raison d'erreurs de valeur de chaîne incorrecte, je suis allé bien et j'ai changé de nombreuses colonnes de texte pour utiliser le utf8jeu de caractères de colonne et la colonne par défaut collate ( utf8_general_ci) afin de les accepter. Cela a corrigé la plupart des erreurs et empêché l'application de recevoir des erreurs SQL lorsqu'elle touchait également des e-mails non latins.

Malgré cela, certains e-mails provoquent toujours des erreurs de valeur de chaîne incorrectes par le programme: (Incorrect string value: '\xE4\xC5\xCC\xC9\xD3\xD8...' for column 'contents' at row 1)

La colonne de contenu est une MEDIUMTEXTdatatybe qui utilise le utf8jeu de caractères de colonne et l' utf8_general_ciassemblage de colonnes. Il n'y a pas d'indicateur que je peux basculer dans cette colonne.

En gardant à l'esprit que je ne veux pas toucher ni même regarder le code source de l'application sauf si c'est absolument nécessaire:

  • Quelle est la cause de cette erreur? (oui, je sais que les e-mails sont pleins d'ordures aléatoires, mais je pensais que utf8 serait assez permissif)
  • Comment puis-je y remédier?
  • Quels sont les effets probables d'un tel correctif?

Une chose que j'ai envisagée était de passer à un varchar utf8 ([un grand nombre]) avec le drapeau binaire activé, mais je ne connais pas assez bien MySQL et je n'ai aucune idée si une telle correction a du sens.

Brian
la source
3
Post-mortem: La solution de RichieHindle a résolu le problème et n'a pas introduit de problèmes supplémentaires pendant son exécution. Cela a peut-être été un peu un hack, mais cela a fonctionné et m'a permis d'éviter de me salir les mains avec des logiciels tiers que je ne comprends pas parfaitement. À ce stade, nous avons mis à jour une version plus récente du logiciel / schéma qui gère correctement tous ces problèmes d'encodage (et est suffisamment nouvelle pour qu'elle soit réellement prise en charge), rendant le hack inutile.
Brian

Réponses:

43

"\xE4\xC5\xCC\xC9\xD3\xD8"n'est pas valide UTF-8. Testé avec Python:

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

Si vous cherchez un moyen d'éviter les erreurs de décodage dans la base de données, le codage cp1252 (alias "Windows-1252" ou "Windows Western European") est le codage le plus permissif qui soit - chaque valeur d'octet est un point de code valide.

Bien sûr, il ne comprendra plus le véritable UTF-8, ni aucun autre encodage non cp1252, mais il semble que vous ne soyez pas trop préoccupé par cela?

RichieHindle
la source
4
Qu'entendez-vous exactement par "Bien sûr, il ne comprendra plus le véritable UTF-8?"
Brian
5
@Brian: Si vous lui dites que vous lui donnez cp1252, et que vous lui donnez en fait l'UTF-8 pour, disons café, cela va mal interpréter cela comme café. Il ne plantera pas, mais il comprendra mal les caractères à bits élevés.
RichieHindle
3
@Richie: La base de données peut appeler les données comme bon lui semble, mais si le code php qui les saisit les met dans une chaîne, cela ne fera pas beaucoup de différence ... n'est-ce pas? Je ne vois pas exactement où le manque de compréhension de l'UTF-8 a un impact.
Brian
7
@Brian: Non, vous avez raison. Le moment où cela ferait une différence serait dans la base de données, par exemple si vous utilisiez une clause ORDER BY dans votre SQL - le tri serait bancal là où vous aviez des caractères non ASCII.
RichieHindle
11
Veuillez décocher cette réponse comme solution, masquer une erreur n'est pas la solution de quoi que ce soit. Retirez la lampe de surchauffe de votre voiture et vous verrez.
David Vartanian
133

Je ne suggérerais pas la réponse de Richies, car vous bousillez les données dans la base de données. Vous ne résoudriez pas votre problème mais essayez de le «cacher» et de ne pas pouvoir effectuer les opérations essentielles de base de données avec les données de merde.

Si vous rencontrez cette erreur, les données que vous envoyez ne sont pas encodées en UTF-8 ou votre connexion n'est pas en UTF-8. Tout d' abord, vérifiez que la source de données (fichier, ...) vraiment est UTF-8.

Ensuite, vérifiez votre connexion à la base de données, vous devez le faire après la connexion:

SET NAMES 'utf8';
SET CHARACTER SET utf8;

Ensuite, vérifiez que les tables dans lesquelles les données sont stockées ont le jeu de caractères 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`
;

Enfin, vérifiez les paramètres de votre base de données:

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

Si la source, le transport et la destination sont UTF-8, votre problème a disparu;)

nico gawenda
la source
1
@Kariem: C'est étrange, car ce paramètre est couvert par la commande SET NAMES, qui équivaut à appeler 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
La deuxième commande devrait être SET CHARACTER SET utf8(pas CHARACTER_SET)
Coder
6
Bien que cette réponse aide à enquêter sur le problème, elle ne répond pas à ce qu'il faut faire pour le résoudre. Je vois "latin1" au lieu de "utf-8".
Vanuan
2
cette réponse est excellente pour expliquer le problème mais très médiocre pour détailler la solution (ce que OP a demandé). @nicogawenda: Quelles sont toutes les requêtes SQL à exécuter pour résoudre complètement le problème? Comment réparer toutes les données préexistantes?
Clint Eastwood
1
"Si la source, le transport et la destination sont UTF-8, votre problème est parti;)" c'était le truc pour moi
suarsenegger
80

Les types utf-8 de MySQL ne sont pas réellement utf-8 appropriés - il n'utilise que jusqu'à trois octets par caractère et ne supporte que le plan multilingue de base (c'est-à-dire pas d'Emoji, pas de plan astral, etc.).

Si vous avez besoin de stocker des valeurs à partir de plans Unicode supérieurs, vous avez besoin des encodages utf8mb4 .

moeffju
la source
9
Je pense que c'est probablement la meilleure solution. Passez à la version 5.5 et remplacez utf8 par utf8mb4 dans les réponses ci-dessus. J'étais en train d'insérer des données utf8 de Twitter contenant des émojis ou d'autres caractères nécessitant 4 octets.
rmarscher le
Supposons que nous n'allons pas passer à la version 5.5. Comment supprimer les erreurs?
Utilisateur
J'ai fait défiler beaucoup trop loin pour cette réponse la plus utile
handheldblender
1
10 ans depuis la question initiale. Sachez que l'encodage utf8 de MySQL n'est pas correct utf8. Utilisez utf8mb4! Il en va de même pour MariaDB. Sinon, vous ne pouvez pas avoir des larmes de joie 😂
Liam
51

La table et les champs ont le mauvais encodage; cependant, vous pouvez les convertir en 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
la source
1
Je pense que celui-ci est la bonne réponse de tous. J'ai deux tables au format utf8 varchar chacune. l'un d'entre eux a l'erreur, l'autre va bien. même si l'utilisateur «update select» fait une copie de la «bonne» colonne utf8 vers une autre table, la même erreur se produit. C'est parce que les deux tables sont créées dans des versions différentes de MySQL.
AiShiguang
Oui! C'était aussi une mauvaise configuration de ma table de base de données. Je pense que cette réponse devrait être la bonne. Mon problème était que l'assemblage sélectionné était utf8_unicode_ci au lieu de utf8_general_ci. Merci :)
jprivillaso
2
Que fait cette réponse ici, devrait être au sommet
Sagun Shrestha
1
celui-ci aide, il vous dit quoi essayer, au lieu de ce qui ne va pas.
Victor Di
Je vous remercie! Cela m'a juste beaucoup aidé j'avais changé la table de classement et je pensais que ça devrait être ça mais les champs étaient toujours de la collation ascii ...
Radu
25

J'ai résolu ce problème aujourd'hui en modifiant la colonne en type «LONGBLOB» qui stocke des octets bruts au lieu de caractères UTF-8.

Le seul inconvénient est que vous devez vous occuper de l'encodage vous-même. Si un client de votre application utilise le codage UTF-8 et un autre utilise le CP1252, vos e-mails peuvent être envoyés avec des caractères incorrects. Pour éviter cela, utilisez toujours le même encodage (par exemple UTF-8) dans toutes vos applications .

Reportez-vous à cette page http://dev.mysql.com/doc/refman/5.0/en/blob.html pour plus de détails sur les différences entre TEXT / LONGTEXT et BLOB / LONGBLOB. Il existe également de nombreux autres arguments sur le Web traitant de ces deux.

Frankshaka
la source
1
Cette solution semble être la solution la plus simple. J'ai essayé quelques autres encodages sans succès.
Simeon Abolarinwa
10

Vérifiez d'abord si votre default_character_set_name est utf8.

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

Si le résultat n'est pas utf8, vous devez convertir votre base de données. Au début, vous devez enregistrer un vidage.

Pour modifier le codage du jeu de caractères en UTF-8 pour toutes les tables de la base de données spécifiée, tapez la commande suivante sur la ligne de commande. Remplacez DBNAME par le nom de la base de données:

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

Pour changer le codage du jeu de caractères en UTF-8 pour la base de données elle-même, tapez la commande suivante à l' invite mysql >. Remplacez DBNAME par le nom de la base de données:

ALTER DATABASE DBNAME CHARACTER SET utf8 COLLATE utf8_general_ci;

Vous pouvez maintenant réessayer d'écrire le caractère utf8 dans votre base de données. Cette solution m'aide lorsque j'essaye de télécharger 200000 lignes de fichier csv dans ma base de données.

Babacar Gningue
la source
8

En général, cela se produit lorsque vous insérez des chaînes dans des colonnes avec un encodage / classement incompatible.

J'ai eu cette erreur lorsque j'avais des TRIGGER, qui héritent du classement du serveur pour une raison quelconque. Et la valeur par défaut de mysql est (au moins sur Ubuntu) latin-1 avec classement suédois. Même si j'avais la base de données et toutes les tables définies sur UTF-8, je n'avais pas encore défini my.cnf:

/etc/mysql/my.cnf:

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

Et cela doit lister tous les déclencheurs avec utf8- *:

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

Et certaines des variables répertoriées par ceci devraient également avoir utf-8- * (pas d'encodage latin-1 ou autre):

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

Bien que votre classement soit défini sur utf8_general_ci, je soupçonne que le codage des caractères de la base de données, de la table ou même de la colonne peut être différent.

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

J'ai eu une erreur similaire ( Incorrect string value: '\xD0\xBE\xDO\xB2. ...' for 'content' at row 1). J'ai essayé de changer le jeu de caractères de la colonne utf8mb4et après cela, l'erreur est devenue 'Data too long for column 'content' at row 1'.
Il s'est avéré que mysql me montre une erreur erronée. J'ai retourné le jeu de caractères de la colonne utf8et changé le type de colonne en MEDIUMTEXT. Après cela, l'erreur a disparu.
J'espère que cela aide quelqu'un.
Au fait MariaDB dans le même cas (j'ai testé le même INSERT là-bas) vient de couper un texte sans erreur.

AVKurov
la source
MySQL aussi j'ai fatigué tellement de choses, j'ai réalisé que mysql ne supportait pas le décodage utf-8 de 4 octets dans cette version et je mourais d'envie de comprendre ce qui en était la cause. Changer le type était apparemment la réponse, une solution immédiate.
Liza
4

Cette erreur signifie que soit vous avez la chaîne avec un codage incorrect (par exemple, vous essayez d'entrer une chaîne codée ISO-8859-1 dans une colonne codée UTF-8), soit la colonne ne prend pas en charge les données que vous essayez d'entrer.

En pratique, ce dernier problème est causé par l'implémentation de MySQL UTF-8 qui ne prend en charge que les caractères UNICODE qui nécessitent 1 à 3 octets lorsqu'ils sont représentés en UTF-8. Voir "Valeur de chaîne incorrecte" lorsque vous essayez d'insérer UTF-8 dans MySQL via JDBC? pour plus de détails.

Mikko Rantalainen
la source
2

La solution pour moi lorsque je rencontre cette valeur de chaîne incorrecte: '\ xF8' pour l'erreur de colonne à l'aide de scriptcase était de m'assurer que ma base de données est configurée pour utf8 general ci, de même que mes classements de champs. Ensuite, quand je fais mon importation de données d'un fichier csv, je charge le csv dans UE Studio puis je l'enregistre au format utf8 et voilà! Cela fonctionne comme un charme, 29000 enregistrements là-dedans aucune erreur. Auparavant, j'essayais d'importer un fichier csv créé par Excel.

mainebrain
la source
2

J'ai essayé toutes les solutions ci-dessus (qui apportent toutes des points valables), mais rien ne fonctionnait pour moi.

Jusqu'à ce que je trouve que mes mappages de champs de table MySQL en C # utilisaient un type incorrect: MySqlDbType.Blob . Je l'ai changé en MySqlDbType.Text et maintenant je peux écrire tous les symboles UTF8 que je veux!

ps Le champ de la table MySQL est du type "LongText". Cependant, lorsque j'ai généré automatiquement les mappages de champs à l'aide du logiciel MyGeneration, il définit automatiquement le type de champ comme MySqlDbType.Blob en C #.

Fait intéressant, j'utilise le type MySqlDbType.Blob avec des caractères UTF8 depuis de nombreux mois sans problème, jusqu'au jour où j'ai essayé d'écrire une chaîne avec des caractères spécifiques.

J'espère que cela aide quelqu'un qui a du mal à trouver une raison de l'erreur.

Ugnius Ramanauskas
la source
1

J'ai ajouté un binaire avant le nom de la colonne et résolu l'erreur de jeu de caractères.

insérer dans les valeurs tableA (binaire stringcolname1);

Richardhe2007
la source
1

Salut, j'ai également eu cette erreur lorsque j'utilise mes bases de données en ligne à partir du serveur godaddy, je pense qu'il a la version mysql de 5.1 ou plus. mais quand je le fais à partir de mon serveur localhost (version 5.7), tout allait bien après avoir créé la table à partir du serveur local et copié sur le serveur en ligne à l'aide de mysql yog, je pense que le problème vient du jeu de caractères

Capture d'écran ici

Hashain Lakshan
la source
1

Pour corriger cette erreur, j'ai mis à niveau ma base de données MySQL vers utf8mb4 qui prend en charge le jeu de caractères Unicode complet en suivant ce tutoriel détaillé . Je suggère de le parcourir attentivement, car il y a pas mal de pièges (par exemple, les clés d'index peuvent devenir trop volumineuses en raison des nouveaux encodages après quoi vous devez modifier les types de champs).

metakermit
la source
1

Il y a de bonnes réponses ici. J'ajoute simplement le mien car j'ai rencontré la même erreur, mais il s'est avéré être un problème complètement différent. (Peut-être en surface la même chose, mais une cause fondamentale différente.)

Pour moi, l'erreur s'est produite pour le champ suivant:

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

Cela finit par être stocké dans la base de données en tant que sérialisation binaire de la URIclasse. Cela n'a soulevé aucun drapeau avec les tests unitaires (en utilisant H2) ou les tests CI / intégration (en utilisant MariaDB4j ), cela a explosé dans notre configuration de production. (Cependant, une fois le problème compris, il était assez facile de voir la mauvaise valeur dans l'instance MariaDB4j; cela n'a tout simplement pas fait sauter le test.) La solution était de créer un mappeur de type personnalisé:

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));
        }
    }
}

Utilisé comme suit:

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

En ce qui concerne Hibernate, il semble qu'il dispose d'un tas de mappeurs de types fournis , y compris pour java.net.URL, mais pas pour java.net.URI(ce dont nous avions besoin ici).

Sander Verhagen
la source
1

Dans mon cas, ce problème a été résolu en changeant l'encodage de la colonne Mysql en 'binaire' (le type de données sera automatiquement changé en VARBINARY). Je ne pourrai probablement pas filtrer ou rechercher avec cette colonne, mais je n'en ai pas besoin.

WilyDen
la source
1

Si vous traitez la valeur avec une fonction de chaîne avant de l'enregistrer, assurez-vous que la fonction peut correctement gérer les caractères multi-octets. Les fonctions de chaîne qui ne peuvent pas faire cela et qui, par exemple, tentent de tronquer peuvent diviser l'un des caractères multi-octets uniques au milieu, ce qui peut provoquer de telles situations d'erreur de chaîne.

En PHP par exemple, vous devrez passer de substrà mb_substr.

WoodrowShigeru
la source
0

Dans mon cas, j'ai d'abord rencontré un '???' dans mon site Web, puis je vérifie le jeu de caractères de Mysql qui est maintenant latin, donc je le change en utf-8, puis je redémarre mon projet, puis j'ai eu la même erreur avec vous, puis j'ai trouvé que j'oublie de changer le jeu de caractères de la base de données et changer en utf-8, boum, ça a marché.

acoder2013
la source
0

J'ai essayé presque toutes les étapes mentionnées ici. Aucun n'a fonctionné. Téléchargé mariadb. Ça a marché. Je sais que ce n'est pas une solution, mais cela pourrait aider quelqu'un à identifier rapidement le problème ou à proposer une solution temporaire.

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

Dans mon cas, Incorrect string value: '\xCC\x88'...le problème était qu'un o-umlaut était dans son état décomposé. Cette question-réponse m'a aidé à comprendre la différence entre et ö. En PHP, le correctif pour moi était d'utiliser la bibliothèque PHP Normalizer . Par exemple, Normalizer::normalize('o¨', Normalizer::FORM_C).

MM.
la source
-2

1 - Vous devez déclarer dans votre connexion la propriété d'encondant UTF8. http://php.net/manual/en/mysqli.set-charset.php .

2 - Si vous utilisez la ligne de commande mysql pour exécuter un script, vous devez utiliser l'indicateur, comme: 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
la source