カラム別に文字コードを設定

使い古されたようなネタですが読み物風の説明書きを書いてしまったので,もったいないので日記にも転載.
こっちが元ネタ(http://ikda.net/fswiki/wiki.cgi?page=MySQL#p13



MySQLではカラム別に文字コードを使用することができます.Windows上にインストールしたMySQLコマンドプロンプトを使用して接続し,"ujis"のカラムと"utf8"のカラムを持つテーブルを作って値をINSERTし,その後SELECTする例を以下に書いて見ました.

まずテーブルを定義しましょう.

mysql> create table t1 (c1 char(1) charset ujis, c2 char(1) charset utf8);
Query OK, 0 rows affected (0.04 sec)

Windowsコマンドプロンプトを使用しているので,"set names sjis"を実行.

mysql> set names sjis;
Query OK, 0 rows affected (0.00 sec)

コマンドプロンプト上から直接ujisやutf8で文字を入力することはできないので,代わりにHEXを使って入れたいと思います.INSERTに使用する予定の文字'あ'のそれぞれHEXを調べます.

mysql> select hex(convert(_sjis 'あ' using ujis));
+-------------------------------------+
| hex(convert(_sjis 'あ' using ujis)) |
+-------------------------------------+
| A4A2                                |
+-------------------------------------+
1 row in set (0.03 sec)

mysql> select hex(convert(_sjis 'あ' using utf8));
+-------------------------------------+
| hex(convert(_sjis 'あ' using utf8)) |
+-------------------------------------+
| E38182                              |
+-------------------------------------+
1 row in set (0.00 sec)

ujisの'あ'は0xA4A2,utfでは0xE38182ということが分かりました.ついでにsjisではどうかというと,

mysql> select hex('あ');
+-----------+
| hex('あ') |
+-----------+
| 82A0      |
+-----------+
1 row in set (0.01 sec)

0x82A0ですね.さてこれを使ってINSERTしてみます.

"_XXX"という風に文字コード名をINSERTする値の前に置きます.

mysql> insert into t1 (c1, c2) values (_ujis 0xA4A2, _utf8 0xE38182);
Query OK, 1 row affected (0.00 sec)

SELECTしてみましょう.まずはちゃんと格納されたかをHEXで確認します.

mysql> select hex(c1), hex(c2) from t1;
+---------+---------+
| hex(c1) | hex(c2) |
+---------+---------+
| A4A2    | E38182  |
+---------+---------+
1 row in set (0.00 sec)

ちゃんと入っていますね.MySQLではConnector/J1のマニュアルにもありますように「サーバへクエリを送信する際は一つの文字エンコーディングのみが指定可能」という原則がありますがこのようにして行えば1度のクエリで異なる文字コードのカラムを操作することが可能です.

さて,最後に普通にSELECTしてみましょう.

mysql> select * from t1;
+------+------+
| c1   | c2   |
+------+------+
| あ   | あ   |
+------+------+
1 row in set (0.00 sec)

ちゃんと'あ'という文字が化けずに表示されましたね.テーブル上ではそれぞれujis,utf8で格納されていますが,sjisと設定しているmysqlclient側でデータをサーバから貰い受ける際に「ujis→sjis」「utf8→sjis」というような自動変換が行われたためです.

以上,こんな感じで.

まあ別にHEXは調べなくとも下記のようにやればできるわけですが,

mysql> insert into t1 (c1, c2) values (convert(_sjis 'あ' using ujis), convert(_sjis 'あ' using utf8));
Query OK, 1 row affected (0.00 sec)

mysql> select * from t1;
+------+------+
| c1   | c2   |
+------+------+
| あ   | あ   |
| あ   | あ   |
+------+------+
2 rows in set (0.00 sec)

Connector/JのようにJava文字コード変換APIが使えるような環境だと,今回手動でHEXで入れたような処理はドライバ側がそのAPIを使って処理しますので.

(※編集後記:上記説明文に含んでいるある表現をメモっておきたかっただけなのですが読み物風にしてみました.)