Come posso trovare caratteri non ASCII in MySQL?


124

Sto lavorando con un database MySQL che ha alcuni dati importati da Excel . I dati contengono caratteri non ASCII (trattini em, ecc.) Nonché ritorni a capo nascosti o avanzamenti riga. C'è un modo per trovare questi record usando MySQL?


8
Ollie Jones ha una risposta molto migliore (controlla in fondo).
Jonathan Arkell

1
@JonathanArkell Non più sul fondo :)
Brilliand

Correzione .. controlla la metà! ;)
Jonathan Arkell

Questa è la risposta @ Jonathan sta parlando stackoverflow.com/a/11741314/792066
Braiam

Risposte:


64

Dipende esattamente da cosa stai definendo "ASCII", ma ti suggerirei di provare una variante di una query come questa:

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

Quella query restituirà tutte le righe in cui columnToCheck contiene caratteri non alfanumerici. Se hai altri caratteri accettabili, aggiungili alla classe di caratteri nell'espressione regolare. Ad esempio, se punti, virgole e trattini sono corretti, modificare la query in:

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

La pagina più rilevante della documentazione di MySQL è probabilmente 12.5.2 Regular Expressions .


3
Non dovresti sfuggire al trattino e al punto? (Poiché hanno significati speciali in un'espressione regolare.) SELECT * FROM tableName WHERE NOT columnToCheck REGEXP '[A-Za-z0-9 \., \ -]';
Tooony

3
@Tooony No, all'interno di un set, un punto significa solo se stesso e il trattino ha un significato speciale solo tra gli altri caratteri. Alla fine del set, significa solo se stesso.
Michael Speer

10
Questa query trova solo tutte le righe in tableName che non contengono un carattere alfanumerico. Questo non risponde alla domanda.
Rob Bailey

8
Questo è per le colonne che non hanno alcun carattere ascii, quindi mancheranno quelle con un mix di caratteri ascii e non ascii. La risposta di seguito da zende controlla uno o più caratteri non ASCII. Questo mi ha aiutato per la maggior parteSELECT * FROM tbl WHERE colname NOT REGEXP '^[A-Za-z0-9\.,@&\(\) \-]*$';
Frank Forte il

1
Questo funziona solo (per me comunque) per trovare stringhe che contengono NESSUNO di quei caratteri. Non trova stringhe che contengono una combinazione di caratteri ASCII e non ASCII.
Ian

236

MySQL fornisce una gestione completa del set di caratteri che può aiutare con questo tipo di problema.

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

La CONVERT(col USING charset)funzione trasforma i caratteri non convertibili in caratteri sostitutivi. Quindi, il testo convertito e non convertito sarà diverso.

Vedi questo per ulteriori discussioni. https://dev.mysql.com/doc/refman/8.0/en/charset-repertoire.html

È possibile utilizzare qualsiasi nome di set di caratteri desiderato al posto di ASCII. Ad esempio, se vuoi scoprire quali caratteri non verranno visualizzati correttamente nella tabella codici 1257 (lituano, lettone, estone) usaCONVERT(columnToCheck USING cp1257)


20
Questa è un'ottima soluzione a questo problema e molto più robusta.
CraigDouglas

5
questo è anche utile per trovare caratteri con accenti (á ä ecc.) o caratteri non appartenenti alla codifica
Glasnhost

3
molto meglio che usare REGEXP (che non sembra funzionare per me per trovare gli accenti) e fornisce anche un semplice meccanismo per fare di nuovo tutto ascii ...
Dirk Conrad Coetsee

1
Questa risposta funziona meravigliosamente e visualizzerà stringhe che contengono caratteri non ASCII anziché solo stringhe che contengono solo caratteri non ASCII. Grazie!
Ian

2
Soluzione eccezionale!
Mad Dog Tannen

93

Puoi definire ASCII come tutti i caratteri che hanno un valore decimale compreso tra 0 e 127 (0x00 - 0x7F) e trovare colonne con caratteri non ASCII utilizzando la seguente query

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

Questa è stata la domanda più completa che ho potuto fare.


3
La migliore risposta finora, ma è ancora più facile così:SELECT * FROM table WHERE LENGTH( column ) != CHAR_LENGTH( column )
SuN

15
-1 Ciò può produrre risultati errati. Supponiamo, ad esempio, che si abbia una colonna UTF-16 contenente 'ā'(codificato dalla sequenza di byte 0x0101) - sarebbe considerato "ASCII" utilizzando questo test: un falso negativo ; anzi, alcuni set di caratteri Non caratteri ASCII codificare all'interno 0x00di 0x7fal che questa soluzione darebbe un falso positivo. NON AFFIDATEVI A QUESTA RISPOSTA!
eggyal

2
@sun: Questo non aiuta affatto - molti set di caratteri sono di lunghezza fissa e quindi LENGTH(column)saranno un multiplo costante CHAR_LENGTH(column)indipendentemente dal valore.
eggyal

49

Questo è probabilmente quello che stai cercando:

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

Dovrebbe restituire tutte le righe in cui COLUMN contiene caratteri non ASCII (o caratteri ASCII non stampabili come la nuova riga).


7
Funziona alla grande per me. "regexp '[^ - ~]'" significa che ha un carattere che è prima dello spazio "" o dopo "~" o ASCII 32 - 126. Tutte le lettere, i numeri e i simboli, ma non le cose non stampabili.
Josh

Puoi anche averlo come una maglietta;) catonmat.net/blog/my-favorite-regex
SamGoody

1
Notare l' avvertenza nella documentazione : " Gli operatori REGEXPe RLIKEfunzionano in modo byte-wise, quindi non sono sicuri multibyte e possono produrre risultati imprevisti con set di caratteri multibyte. Inoltre, questi operatori confrontano i caratteri in base ai loro valori byte e i caratteri accentati potrebbero non essere paragonabili allo stesso modo anche se un dato confronto li considera uguali. "
eggyal

1
grazie per questo. quello che mi chiedo è come sostituire un carattere sostitutivo - ad es.
mars-o

1
@ mars-o - il rombo nero indica un carattere utf8 non valido. Ulteriori discussioni qui
Rick James

14

Un carattere mancante dagli esempi di tutti sopra è il carattere di terminazione (\ 0). Questo è invisibile all'output della console MySQL e non è rilevabile da nessuna delle query precedentemente menzionate. La query per trovarlo è semplicemente:

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

4

Basandomi sulla risposta corretta, ma tenendo conto anche dei caratteri di controllo ASCII, la soluzione che ha funzionato per me è questa:

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

Fa la stessa cosa: cerca le violazioni dell'intervallo ASCII in una colonna, ma ti consente anche di cercare i caratteri di controllo, poiché utilizza la notazione esadecimale per i punti di codice. Poiché non vi è alcun confronto o conversione (a differenza della risposta di @ Ollie), anche questo dovrebbe essere significativamente più veloce. (Soprattutto se MySQL esegue la terminazione anticipata sulla query regex, cosa che dovrebbe sicuramente.)

Evita inoltre di restituire campi di lunghezza zero. Se desideri una versione leggermente più lunga che possa funzionare meglio, puoi utilizzare questa:

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

Esegue un controllo separato per la lunghezza per evitare risultati di lunghezza zero, senza considerarli per un passaggio di regex. A seconda del numero di voci di lunghezza zero che hai, questo potrebbe essere significativamente più veloce.

Nota che se il tuo set di caratteri predefinito è qualcosa di bizzarro in cui 0x00-0xFF non si associa agli stessi valori di ASCII (esiste un set di caratteri di questo tipo da qualche parte?), Ciò restituirebbe un falso positivo. Altrimenti, divertiti!


1
00-FF include tutti i possibili valori a 8 bit, che è ciò che REGEXPsta controllando. Quindi è garantito che corrisponda sempre. Inoltre ^$probabilmente non è quello che volevi.
Rick James

Sicuramente la migliore soluzione REGEXP per trovare tutti i caratteri a 8 bit ma non è buona come la soluzione CONVERT (col USING charset) che consentirà anche i caratteri di controllo limitando i caratteri di visualizzazione a un set di caratteri specifico.
Ian

1

Prova a utilizzare questa query per cercare record di caratteri speciali

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

0

La risposta di @zende era l'unica che copriva le colonne con un mix di caratteri ascii e non ascii, ma aveva anche quella problematica cosa esadecimale. Ho usato questo:

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

0

In Oracle possiamo usare di seguito.

SELECT * FROM TABLE_A WHERE ASCIISTR(COLUMN_A) <> COLUMN_A;

-2

per questa domanda possiamo usare anche questo metodo:

Domanda da sql zoo:
Trova tutti i dettagli del premio vinto da PETER GRÜNBERG

Caratteri non ASCII

ans: seleziona * da nobel dove vincitore like'P% GR% _% berg ';


1
Qual è il collegamento alla domanda?
Nico Haase
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.