Konvertering af MySQL tabeller fra latin1 til UTF-8
Dette blogindlæg, er et indlæg som jeg oprindeligt har skrevet kladden til for cirka 7 år siden, men som jeg aldrig fik udgivet. Derfor kan det meget vel være, at der er kommet en smartere måde at gøre tingene på, eller at det jeg beskriver ganske enkelt ikke virker mere. Jeg synes dog stadig at det var værd at dele, hvis der nu skulle sidde en anden med samme problemstilling som jeg havde dengang.
Det seneste stykke tid har jeg lagt en del timer i, at konvertere vores database på Xboxlife.dk og PSlife.dk til UTF-8 format. Hidtil har databasen af historiske årsager desværre været lidt rodet, da selve databasen var i 'latin1' (ISO-8859-1) og nogle af tabellerne var i latin1 imens andre var i UTF-8 format. For ligesom at få styr på tingene, så havde vi et ønske om at få ensrettet det hele, så det fremover kun ligger i UTF-8, her vil jeg fortælle lidt om hvordan vi endte med at lave løsningen.
I dette tilfælde, så laver jeg eksporten fra en produktionsdatabase og importerer den derefter i vores testdatabase. Hvis du drager inspiration af dette blogindlæg, så skal du derfor være opmærksom på hvilken database du vil IMPORTERE til, så du ikke får overskrevet din produktionsdatabase ved en fejl. Jeg valgte i øvrigt at lave hele konverterings-processen med både export, konvertering og import af data ind i et shell-script, så vi nemt kan lave en konverteret klon af produktionsdatabasen til testdatabasen (det er pt. kun testdatabasen der bruger UTF-8 overalt).
Export af de eksisterende tabeller
Da en stor del af tabellerne og ikke mindst indholdet i databasen i forvejen består af UTF-8 tabeller, så besluttede jeg mig for at lave en fuld dump af hele databasen med utf-8 som charset. Samtidig angiver jeg --skip-set-charset, så databasens standard charset ikke kommer med i dumpet fra mysqldump.
mysqldump -uusername -p -h127.0.0.1 --default-character-set=utf8 --skip-set-charset database > fulldump.sql
For at fjerne alle de steder i dumpet hvor latin1 er, så brugte jeg 'sed':
/usr/bin/sed -i .bk 's/ DEFAULT CHARSET\=latin1//g' fulldump.sql
Derefter laver jeg et seperat dump af alle de tabeller som jeg på forhånd ved er i latin1 format, og kører dem igennem 'cat' og 'iconv' for at få dem konverteret til UTF-8 format, kører hvert dump igennem 'sed' og sletter .bk filen til sidst, den er desværre nødvendig for at få sed til at gøre det jeg ville:
for i in tabel1 tabel2 tabel3
do
mysqldump -uusername -p -h127.0.0.1 --default-character-set=latin1 --skip-set-charset databasename $i > dump_$i.sql
/bin/cat dump_$i.sql | /usr/local/bin/iconv -f ISO-8859-1 -t UTF-8 > dump_$i.utf8.sql
/usr/bin/sed -i .bk 's/ DEFAULT CHARSET\=latin1//g' dump_$i.utf8.sql
/bin/rm dump_$i.utf8.sql.bk
done
Opret ny database og import af data i UTF-8
Når det er overstået, så er det tid til at oprette den nye database som selvfølgelig skal være i UTF-8 format:
CREATE DATABASE testdb CHARACTER SET utf8 COLLATE utf8_general_ci;
GRANT ALL ON testdb.* TO testusername@localhost IDENTIFIED BY 'password';
Derefter importer jeg det fulde dump, velvidende at en del af tabellerne nu vil blive korrupte, men dem sletter jeg bagefter og importerer de rigtige som vi lige har konverteret til UTF-8. På grund af antallet af latin1 tableller kontra antallet af UTF-8 tabeller, så var dette den nemmeste løsning for mig. Man kunne selvfølgelig også bare have valgt at dumpe UTF-8 og latin1 tabellerne seperat og dermed undgå at skulle lave dobbelt import.
mysql -utestdb -p -h127.0.0.1 -f --default-character-set=utf8 testdb < fulldump.sql
Derefter var tabellerne konverteret til UTF-8.