MySQL で文字コードが関わる 3 か所
- 列・テーブル: データを保存する文字コードです。
utf8mb4のほか、古いシステムではlatin1、sjis、cp932、ujis(EUC-JP)も使われています。 - 接続: アプリと MySQL がやり取りする文字コードです。
SET NAMES utf8mb4や接続設定で指定します。 - ファイル: インポートやエクスポートで使う文字コードです。phpMyAdmin ではインポート・エクスポート画面でファイルの文字セットを選べます。コマンドラインで結果が化ける場合は PowerShell の文字化け も参考になります。
3 か所のどれかが食い違うと文字が化けます。症状は大きく 2 種類に分かれ、直せるかどうかも違います。
日本語が ???? になる場合
列や接続の文字コードが日本語を表せないと、MySQL は文字を ? に置き換えて保存します。よくあるのは、列や接続が latin1 のままになっているケースです。接続が cp932 や sjis の場合も、CP932 にない絵文字などは ? になります。
utf8(実体は 3 バイトまでの utf8mb3)の列に絵文字や 𠮷 のような 4 バイトの文字を入れると、Incorrect string value エラーになるか、設定によっては文字が欠けます。いったん ? として保存された文字は情報が失われているため、Mojibuster でも元に戻せません。
山田 のように化ける場合
UTF-8 の文章が latin1 の接続で latin1 の列に書き込まれると、アプリでは正しく見えても、phpMyAdmin やエクスポートでは 山田 のように表示されます。この場合はバイトが残っているので修正できます。
文字化け
"1","山田太郎","大阪府","å–¶æ¥éƒ¨"
修正後
"1","山田太郎","大阪府","営業部"
文字コードを確認する
SHOW VARIABLES LIKE 'character_set%';で、サーバーと接続の設定がわかります。SHOW CREATE TABLE customers;で、テーブルと列の文字コードがわかります。SELECT name, HEX(name) FROM customers LIMIT 5;で実際のバイトを確認できます。utf8mb4の列でE5B1B1なら正しい「山」、C3A5C2B1C2B1ならすでに化けたå±±です。
エクスポートやダンプを修正する
- phpMyAdmin でテーブルを SQL または CSV で書き出すか、
mysqldump --default-character-set=utf8mb4を使います。 - 上の枠にファイルをドロップします。Mojibuster は化けた箇所だけを直し、正しい文字には手を加えません。
- 変更箇所 で修正内容を確認し、ファイルをダウンロードします。
utf8mb4のテーブルに取り込み、インポート画面の文字セットはutf-8を選びます。- 本番のテーブルを置き換える前に、まずコピーで試してください。
ダンプはブラウザーの外に出ないので、顧客データを含むファイルでも安心して扱えます。書き出した CSV を Excel で開くと化ける場合は、Excel の CSV 文字化け を参照してください。
原因を直す
- 新しいテーブルは
DEFAULT CHARSET=utf8mb4で作ります。 - アプリの接続も
utf8mb4にします。PHP なら PDO の DSN にcharset=utf8mb4を付けます。 latin1の列に UTF-8 のバイトが入っている場合、CONVERT TOで直接変換してはいけません。もう一度エンコードされ、二重に化けます。安全なのはバイナリ型を経由する方法です。まずMODIFY name VARBINARY(255)、次にMODIFY name VARCHAR(255) CHARACTER SET utf8mb4を実行します。sjisやujisの列に日本語が正しく入っている場合は、ALTER TABLE customers CONVERT TO CHARACTER SET utf8mb4でそのまま変換できます。
よくある質問
アプリでは正しく表示されるのに、phpMyAdmin では化けるのはなぜですか?
アプリと MySQL が同じ間違いを 2 回しているからです。アプリは UTF-8 を latin1 の接続で書き込み、同じ接続で読み戻すので正しく見えます。phpMyAdmin は正しい接続で読むため、実際に保存されている化けた状態が見えます。
照合順序(collation)は何を選べばよいですか?
まず文字コードを utf8mb4 にすることが大切です。照合順序によっては日本語の比較に癖があり、utf8mb4_general_ci などでは 🍣 と 🍺 が同じ文字として扱われる「寿司ビール問題」、MySQL 8 の標準 utf8mb4_0900_ai_ci では「ハ」と「パ」が区別されない問題が知られています。区別が必要な列には utf8mb4_ja_0900_as_cs や utf8mb4_bin を検討してください。
MariaDB でも同じですか?
はい。文字コードの扱いは MySQL と同じで、上のコマンドもそのまま使えます。
どのくらいの大きさのダンプまで扱えますか?
1 ファイル 100 MB までです。大きなデータベースはテーブルごとに書き出してください。