Mal eben schnell MySQL-Zeichensatzprobleme fixen

Heute lag eine Anfrage einer Kundin auf meinem Tisch, die eine Datenbank voller MySQL-Tabellen hatte. Der Zeichensatz der Datenbank und aller Tabellen und Spalten war latin1_german_ci. Dumm nur, dass die Applikation überall UTF8-kodierte Werte reingeschrieben hat – was hier und da so ein bisschen funktionierte, an anderen Stellen aber so gar nicht. In phpMyAdmin wurden alle Umlaute aber fehlerhaft dargestellt, und damit stand dann auch fest, dass da einfach Murks passiert war (denn wir wissen ja, phpMyAdmin hat immer recht, siehe hier).

Nun ist aber das Problem, dass die nachträgliche Änderungen der Spalten in phpMyAdmin erstens mühselig ist und zweitens auch gar nichts bringt, weil MySQL dabei die Inhalte der Spalten auch gleich (in seine Sinne) korrekt konvertiert. Die einzige Möglichkeit ist, die Spalte auf eine binäre Spalte vom Typ BLOB zu ändern, weil hierbei die Zeichensatzangabe verlorengeht, was wir hier auch explizit wollen – sie ist ja falsch. Das ist aber noch viel unglaublich aufwendiger.

Auf der Shell lässt sich das Problem aber schließlich trivial lösen. Zunächst dumpen wir die gesamte Datenbank, und dabei geben wir an, dass latin1 als Zeichensatz verwendet werden soll – auf diese Weise dumpt MySQL die Daten so (falsch), wie sie in den Spalten stehen; da sind sie ja als latin1 kodiert. Dann ändern wir alle Kollations- und alle Zeichensatzangaben im SQL-Dump von latin1 auf utf8 – wobei die Daten, genauer gesagt die Bytes aber ja unverändert bleiben. Anschließend wird alles wieder in MySQL gefüttert.

Und so sieht’s aus (es wird eine .my.cnf mit hinterlegten Zugangsdaten vorausgesetzt, damit keine Passworteingabe erfolgen muss):

mysqldump --default-character-set=latin1 mydatabase mydatabase.sql

cat mydatabase.sql |
  sed 's/latin1_german_ci/utf8_general_ci/g;' |
  sed 's/latin1/utf8/g;' |
  mysql mydatabase

Fertig! In phpMyAdmin sicherheitshalber kontrollieren, dass alle Spalten als utf8 kodiert sind und gleichzeitig auch die Umlaute korrekt angezeigt werden. Und da wir die Zeichensatzänderung nicht bei Dumpen, sondern beim Einspielen des Dumps „on the fly“ machen, liegt mit mydatabase.sql dann auch gleich noch ein Backup des Originalzustands vor, falls alles schiefgehen sollte.

Problematisch wird die Sache nur, wenn nur einige Tabellen oder – noch schlimmer – nur einige Spalten einiger Tabellen falsch kodiert sind. In diesem Fall wäre dann doch eher professionelle Hilfe gefragt – oder viel Handarbeit. 😉