139 votes

Comment puis-je trouver des caractères non ASCII dans MySQL ?

Je travaille avec une base de données MySQL dont certaines données sont importées de Excel . Les données contiennent des données non ASCII (tirets, etc.) ainsi que les retours de chariot ou les sauts de ligne cachés. Existe-t-il un moyen de trouver ces enregistrements à l'aide de MySQL ?

8 votes

Ollie Jones a une bien meilleure réponse (voir en bas de page).

1 votes

@JonathanArkell Plus en bas maintenant :)

0 votes

Correction vérifiez le milieu ! ;)

281voto

Ollie Jones Points 20488

MySQL offre une gestion complète des jeux de caractères qui peut aider à résoudre ce type de problème.

SELECT whatever
  FROM tableName 
 WHERE columnToCheck <> CONVERT(columnToCheck USING ASCII)

El CONVERT(col USING charset) transforme les caractères non convertibles en caractères de remplacement. Le texte converti et le texte non converti seront alors inégaux.

Voir ceci pour plus de discussion. https://dev.mysql.com/doc/refman/8.0/en/charset-repertoire.html

Vous pouvez utiliser le nom du jeu de caractères de votre choix à la place de l'ASCII. Par exemple, si vous voulez savoir quels caractères ne seront pas rendus correctement dans la page de code 1257 (lituanien, letton, estonien), utilisez CONVERT(columnToCheck USING cp1257)

23 votes

C'est une excellente solution à ce problème et beaucoup plus robuste.

6 votes

Ceci est également utile pour trouver les caractères avec des accents (á ä etc) ou les caractères n'appartenant pas à l'encodage.

3 votes

C'est beaucoup mieux que d'utiliser REGEXP (qui ne semble pas fonctionner pour moi pour trouver les accents) et cela fournit également un mécanisme simple pour rendre tout ascii à nouveau...

92voto

zende Points 639

Vous pouvez définir l'ASCII comme étant tous les caractères ayant une valeur décimale de 0 à 127 (0x00 - 0x7F) et rechercher les colonnes contenant des caractères non ASCII en utilisant la requête suivante

SELECT * FROM TABLE WHERE NOT HEX(COLUMN) REGEXP '^([0-7][0-9A-F])*$';

C'est la demande la plus complète que j'ai pu formuler.

4 votes

La meilleure réponse jusqu'à présent, mais c'est encore plus simple comme ça : SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )

16 votes

-1 Cela peut donner des résultats erronés. Supposons, par exemple, que l'on dispose d'une colonne UTF-16 contenant 'a' (encodé par la séquence d'octets 0x0101 ) - il serait considéré comme "ASCII" en utilisant ce test : un faux négatif En effet, certains jeux de caractères ne codent pas les caractères ASCII dans les limites de l'espace disponible. 0x00 a 0x7f auquel cas cette solution donnerait un faux positif. NE VOUS FIEZ PAS À CETTE RÉPONSE !

2 votes

@sun : Cela n'aide pas du tout - de nombreux jeux de caractères sont de longueur fixe et donc LENGTH(column) sera un multiple constant de CHAR_LENGTH(column) quelle que soit la valeur.

72voto

Chad Birch Points 39087

Cela dépend exactement de ce que vous définissez comme "ASCII", mais je vous suggère d'essayer une variante d'une requête comme celle-ci :

SELECT * FROM tableName WHERE columnToCheck NOT REGEXP '[A-Za-z0-9]';

Cette requête renverra toutes les lignes où columnToCheck contient des caractères non alphanumériques. Si d'autres caractères sont acceptables, ajoutez-les à la classe de caractères dans l'expression régulière. Par exemple, si les points, les virgules et les traits d'union sont acceptables, modifiez la requête en :

SELECT * FROM tableName WHERE columnToCheck NOT REGEXP '[A-Za-z0-9.,-]';

La page la plus pertinente de la documentation MySQL est probablement 12.5.2 Expressions régulières .

0 votes

Merci, je vais y jeter un coup d'œil. Je n'ai pas beaucoup d'expérience avec les expressions régulières en SQL, ce sera donc une bonne occasion d'apprendre.

3 votes

Ne devriez-vous pas échapper le trait d'union et le point ? (Puisqu'ils ont des significations spéciales dans une expression régulière) SELECT * FROM tableName WHERE NOT columnToCheck REGEXP '[A-Za-z0-9 \. ,\-]' ;

3 votes

@Tooony Non, à l'intérieur d'un ensemble, un point ne signifie que lui-même et le tiret n'a de signification spéciale qu'entre d'autres caractères. À la fin d'un ensemble, il ne signifie que lui-même.

50voto

C'est probablement ce que vous recherchez :

select * from TABLE where COLUMN regexp '[^ -~]';

Elle doit renvoyer toutes les lignes où COLUMN contient des caractères non ASCII (ou des caractères ASCII non imprimables tels que les nouvelles lignes).

7 votes

Cela fonctionne très bien pour moi. "regexp '[^ -~]'" signifie que le caractère est avant l'espace " " ou après "~" ou ASCII 32 - 126. Toutes les lettres, tous les chiffres et tous les symboles, mais pas de choses non imprimables.

0 votes

Vous pouvez même l'obtenir en tee-shirt ;) catonmat.net/blog/my-favorite-regex

2 votes

Notez le avertissement en el documentation : " El REGEXP y RLIKE fonctionnent par octet, ils ne sont donc pas sûrs pour les caractères multi-octets et peuvent produire des résultats inattendus avec des jeux de caractères multi-octets. De plus, ces opérateurs comparent les caractères par leur valeur en octets et les caractères accentués peuvent ne pas être comparés comme égaux même si une collation donnée les traite comme tels. "

15voto

Rob Bailey Points 330

Un caractère manquant dans tous les exemples ci-dessus est le caractère de terminaison ( \0 ). Il est invisible dans la sortie de la console MySQL et ne peut être découvert par aucune des requêtes mentionnées précédemment. La requête pour le trouver est simplement :

select * from TABLE where COLUMN like '%\0%';

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X