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

124

Je travaille avec une base de données MySQL qui contient des données importées d' Excel . Les données contiennent des caractères non ASCII (tirets em, etc.) ainsi que des retours chariot masqués ou des sauts de ligne. Existe-t-il un moyen de trouver ces enregistrements en utilisant MySQL?

Ed Mays
la source
8
Ollie Jones a une bien meilleure réponse (vérifiez le bas).
Jonathan Arkell
1
@JonathanArkell Plus en bas :)
Brilliand
Correction .. vérifiez le milieu! ;)
Jonathan Arkell
C'est la réponse @Jonathan parle de stackoverflow.com/a/11741314/792066
Braiam

Réponses:

64

Cela dépend exactement de ce que vous définissez comme "ASCII", mais je suggérerais 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 vous avez d'autres caractères acceptables, ajoutez-les à la classe de caractères de l'expression régulière. Par exemple, si les points, les virgules et les traits d'union sont corrects, remplacez la requête par:

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 .

Chad Birch
la source
3
Ne devriez-vous pas échapper au trait d'union et au 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 \., \ -]';
Tooony
3
@Tooony Non, à l'intérieur d'un ensemble, un point signifie simplement lui-même et le tiret n'a qu'une signification particulière entre les autres caractères. À la fin de l'ensemble, cela ne signifie que lui-même.
Michael Speer
10
Cette requête ne trouve que toutes les lignes de tableName qui ne contiennent pas de caractère alphanumérique. Cela ne répond pas à la question.
Rob Bailey
8
C'est pour les colonnes qui n'ont pas du tout de caractères ascii, donc il manquera celles avec un mélange de caractères ascii et non-ascii. La réponse ci-dessous de zende vérifie un ou plusieurs caractères non-ascii. Cela m'a aidé pour la plupartSELECT * FROM tbl WHERE colname NOT REGEXP '^[A-Za-z0-9\.,@&\(\) \-]*$';
Frank Forte
1
Cela ne fonctionne (pour moi en tout cas) que pour trouver des chaînes qui ne contiennent AUCUN de ces caractères. Il ne trouve pas les chaînes contenant un mélange de caractères ASCII et non ASCII.
Ian le
236

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

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

La CONVERT(col USING charset)fonction transforme les caractères non convertibles en caractères de remplacement. Ensuite, le texte converti et non converti sera inégal.

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

Vous pouvez utiliser n'importe quel nom de jeu de caractères que vous souhaitez à la place de ASCII. Par exemple, si vous voulez savoir quels caractères ne s'afficheront pas correctement dans la page de codes 1257 (lituanien, letton, estonien), utilisezCONVERT(columnToCheck USING cp1257)

O. Jones
la source
20
C'est une excellente solution à ce problème et bien plus robuste.
CraigDouglas
5
ceci est également utile pour trouver des caractères avec des accents (á ä etc.) ou des caractères n'appartenant pas à l'encodage
Glasnhost
3
bien mieux que d'utiliser REGEXP (qui ne semble pas fonctionner pour moi pour trouver des accents) et fournit également un mécanisme simple pour tout rendre à nouveau ascii ...
Dirk Conrad Coetsee
1
Cette réponse fonctionne à merveille et fera apparaître des chaînes contenant des caractères non ASCII plutôt que des chaînes contenant uniquement des caractères non ASCII. Je vous remercie!
Ian le
2
Solution exceptionnelle!
Mad Dog Tannen
93

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

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

C'était la requête la plus complète que je puisse proposer.

zende
la source
3
Meilleure réponse à ce jour, mais c'est encore plus facile comme ça:SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )
SuN
15
-1 Cela peut donner des résultats erronés. Supposons, par exemple, que l'on ait une colonne UTF-16 contenant 'ā'(encodée par la séquence d'octets 0x0101) - elle serait réputée "ASCII" en utilisant ce test: un faux négatif ; en effet, certains jeux de caractères ne codent pas les caractères ASCII à l'intérieur 0x00de 0x7fsorte que cette solution donnerait un faux positif. NE VOUS FIEZ PAS À CETTE RÉPONSE!
eggyal
2
@sun: Cela n'aide pas du tout - de nombreux jeux de caractères sont de longueur fixe et LENGTH(column)seront donc un multiple constant CHAR_LENGTH(column)quelle que soit la valeur.
eggyal
49

C'est probablement ce que vous recherchez:

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

Il doit renvoyer toutes les lignes où COLUMN contient des caractères non ASCII (ou des caractères ASCII non imprimables tels que le saut de ligne).

Peter Mortensen
la source
7
Fonctionne très bien pour moi. "regexp '[^ - ~]'" signifie a un caractère qui est avant l'espace "" ou après "~" ou ASCII 32 - 126. Toutes les lettres, chiffres et symboles, mais pas de choses non imprimables.
Josh
Vous pouvez même l'obtenir sous forme de tee-shirt;) catonmat.net/blog/my-favorite-regex
SamGoody
1
Notez l' avertissement dans la documentation : " Les opérateurs REGEXPet RLIKEfonctionnent par octet, ils ne sont donc pas sécurisés sur plusieurs octets et peuvent produire des résultats inattendus avec des jeux de caractères multi-octets. En outre, ces opérateurs comparent les caractères par leurs valeurs d'octets et les caractères accentués peuvent ne pas être comparables même si un classement donné les traite comme égaux. "
eggyal
1
Merci pour cela. ce que je me demande, c'est comment remplacer un personnage de remplacement - par exemple â
mars-o
1
@ mars-o - le losange noir indique un caractère utf8 invalide. Plus de discussion ici
Rick James
14

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

select * from TABLE where COLUMN like '%\0%';
Rob Bailey
la source
4

Sur la base de la bonne réponse, mais en tenant également compte des caractères de contrôle ASCII, la solution qui a fonctionné pour moi est la suivante:

SELECT * FROM `table` WHERE NOT `field` REGEXP  "[\\x00-\\xFF]|^$";

Il fait la même chose: recherche les violations de la plage ASCII dans une colonne, mais vous permet également de rechercher des caractères de contrôle, car il utilise la notation hexadécimale pour les points de code. Comme il n'y a pas de comparaison ou de conversion (contrairement à la réponse de @ Ollie), cela devrait également être beaucoup plus rapide. (Surtout si MySQL effectue une résiliation anticipée de la requête regex, ce qu'il devrait certainement.)

Cela évite également de renvoyer des champs de longueur nulle. Si vous voulez une version légèrement plus longue qui pourrait fonctionner mieux, vous pouvez utiliser ceci à la place:

SELECT * FROM `table` WHERE `field` <> "" AND NOT `field` REGEXP  "[\\x00-\\xFF]";

Il effectue une vérification séparée de la longueur pour éviter les résultats de longueur nulle, sans les considérer pour une passe d'expression régulière. Selon le nombre d'entrées de longueur nulle que vous avez, cela pourrait être beaucoup plus rapide.

Notez que si votre jeu de caractères par défaut est quelque chose de bizarre où 0x00-0xFF ne correspond pas aux mêmes valeurs que ASCII (existe-t-il un tel jeu de caractères quelque part?), Cela renverrait un faux positif. Sinon, profitez-en!

Mahmoud Al-Qudsi
la source
1
00-FF inclut toutes les valeurs 8 bits possibles, ce qui REGEXPest la vérification. Par conséquent, il est garanti de toujours correspondre. Ce ^$n'est probablement pas non plus ce que vous vouliez.
Rick James
Certainement la meilleure solution REGEXP pour trouver tous les caractères 8 bits mais pas aussi bonne que la solution CONVERT (col USING charset) qui permettra également de contrôler les caractères tout en limitant les caractères d'affichage à un jeu de caractères spécifique.
Ian
1

Essayez d'utiliser cette requête pour rechercher des enregistrements de caractères spéciaux

SELECT *
FROM tableName
WHERE fieldName REGEXP '[^a-zA-Z0-9@:. \'\-`,\&]'
Sachin
la source
0

La réponse de @ zende était la seule qui couvrait les colonnes avec un mélange de caractères ascii et non ascii, mais il y avait aussi ce problème hexadécimal. J'ai utilisé ceci:

SELECT * FROM `table` WHERE NOT `column` REGEXP '^[ -~]+$' AND `column` !=''
chiliNUT
la source
0

Dans Oracle, nous pouvons utiliser ci-dessous.

SELECT * FROM TABLE_A WHERE ASCIISTR(COLUMN_A) <> COLUMN_A;
Malaka Gunawardhana
la source
-2

pour cette question, nous pouvons également utiliser cette méthode:

Question de sql zoo:
Retrouvez tous les détails du prix remporté par PETER GRÜNBERG

Caractères non ASCII

ans: sélectionnez * de nobel où gagnant comme «P% GR% _% berg»;

hemu123
la source
1
Où est le lien avec la question?
Nico Haase