なからなLife

geekに憧れと敬意を抱きながら、SE、ITコンサル、商品企画、事業企画、管理会計、総務・情シス、再び受託でDB屋さんと流浪する人のブログです。

MySQLでキャラクタセットを変更する

キャラクタセットはカラムレベルで持っている

Oracleの場合はデータベースレベルで持っているキャラクタセット定義ですが、MySQLの場合、キャラクタセットはカラムレベルで持っています。

ですので、同じデータベース、テーブルの中で、カラムによって別々のキャラクタセットを持つこともMySQLでは可能です。(誰がそんな使い方するんだよ)


そして、データベース、テーブルレベルで「デフォルトの」キャラクタセットは定義できますが、あくまでカラム定義時に明示指定しなかった時の為のデフォルト値でしかありません。

キャラクタセットは「変更」できるか

Oracleの場合、10gから「ALTER DATABASE CHARACTER SET」文は廃止されているようですね。

MySQL的には、「ALTER DATABASE CHARACTER SET」で「デフォルトキャラクタセット」が変更できますが、この文では、カラムレベルの定義までは変更されませんし、当然格納されているデータにも波及しません。

MySQLで、実際にキャラクタセット定義を持っている「カラムレベル」での変更を行うには、以下のDDLで対応しています。

ALTER TABLE CHANGE 旧カラム名 新カラム名 新データ型 CHARACTER SET 新キャラクタセット名


ただし、データが格納されている場合、格納されているデータが変更後のキャラクタセットと互換性がないと、エラーがになります。

実験

以下、utf8mb4で作成したカラムに、日本語の文字を格納して、latin1への変更を試みた結果です。

mysql> CREATE DATABASE test_char_change DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_bin;
Query OK, 1 row affected (0.00 sec)

mysql> CREATE TABLE test_char_change.tbl_a (
    ->   col1 int(11) NOT NULL DEFAULT '0' PRIMARY KEY,
    ->   col2 varchar(10) DEFAULT NULL
    -> ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;
Query OK, 0 rows affected (0.11 sec)

mysql> SHOW CREATE TABLE test_char_change.tbl_a\G
*************************** 1. row ***************************
       Table: tbl_a
Create Table: CREATE TABLE `tbl_a` (
  `col1` int(11) NOT NULL DEFAULT '0',
  `col2` varchar(10) COLLATE utf8mb4_bin DEFAULT NULL,
  PRIMARY KEY (`col1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
1 row in set (0.00 sec)

mysql> SELECT table_schema,table_name,column_name,column_type,character_set_name,collation_name FROM information_schema.columns WHERE table_schema = 'test_char_change';
+------------------+------------+-------------+-------------+--------------------+----------------+
| table_schema     | table_name | column_name | column_type | character_set_name | collation_name |
+------------------+------------+-------------+-------------+--------------------+----------------+
| test_char_change | tbl_a      | col1        | int(11)     | NULL               | NULL           |
| test_char_change | tbl_a      | col2        | varchar(10) | utf8mb4            | utf8mb4_bin    |
+------------------+------------+-------------+-------------+--------------------+----------------+
2 rows in set (0.00 sec)

mysql> INSERT INTO test_char_change.tbl_a (col1,col2) VALUES (1,'abcde');
Query OK, 1 row affected (0.00 sec)

mysql> INSERT INTO test_char_change.tbl_a (col1,col2) VALUES (2,'あいうえお');
Query OK, 1 row affected (0.01 sec)

mysql> SELECT * FROM test_char_change.tbl_a;
+------+-----------------+
| col1 | col2            |
+------+-----------------+
|    1 | abcde           |
|    2 | あいうえお      |
+------+-----------------+
2 rows in set (0.00 sec)

mysql> ALTER TABLE test_char_change.tbl_a CHANGE col2 col2 varchar(10) CHARACTER SET latin1;
ERROR 1366 (HY000): Incorrect string value: '\xE3\x81\x82\xE3\x81\x84...' for column 'col2' at row 2
mysql> DELETE FROM test_char_change.tbl_a WHERE col1 = 2;
Query OK, 1 row affected (0.00 sec)

mysql> SELECT * FROM test_char_change.tbl_a;
+------+-------+
| col1 | col2  |
+------+-------+
|    1 | abcde |
+------+-------+
1 row in set (0.00 sec)

mysql> ALTER TABLE test_char_change.tbl_a CHANGE col2 col2 varchar(10) CHARACTER SET latin1;
Query OK, 1 row affected (0.06 sec)
Records: 1  Duplicates: 0  Warnings: 0

mysql> SELECT table_schema,table_name,column_name,column_type,character_set_name,collation_name FROM information_schema.columns WHERE table_schema = 'test_char_change';
+------------------+------------+-------------+-------------+--------------------+-------------------+
| table_schema     | table_name | column_name | column_type | character_set_name | collation_name    |
+------------------+------------+-------------+-------------+--------------------+-------------------+
| test_char_change | tbl_a      | col1        | int(11)     | NULL               | NULL              |
| test_char_change | tbl_a      | col2        | varchar(10) | latin1             | latin1_swedish_ci |
+------------------+------------+-------------+-------------+--------------------+-------------------+
2 rows in set (0.00 sec)

まとめ

  • MySQLのキャラクタセットは、カラムレベルで持っている。
  • カラムより上のレベルは、あくまで「デフォルト」なので、変更しても既存カラムに波及しない。
  • ALTER文でキャラクタセットの変更は可能。
  • ただし、格納済データのキャラクタセットが変更後のキャラクタセットと互換性がないと、エラーになる。

ていうか、キャラクタセットを途中で変更する事自体、避けたいよねー。

やさしく学べるMySQL運用・管理入門【5.7対応】

やさしく学べるMySQL運用・管理入門【5.7対応】