MySQLのvarcharについてまとめています。
以下、サンプルデータベースとしてEmployeesを、MySQLのバージョンは5.7.28を前提としています。
MySQLのvarcharとcharの違い 末尾の空白に注意
MySQLの文字列を扱うデータ型には、varcharとcharがあります。何がどう違うんでしょうか?
varcharはサイズ可変型、charはサイズ固定型です。内部的な処理によって、文字列の末尾に空白をつけた場合に、動きが変わってきます。
テスト用のテーブルvchatestを作って、動きを確かめてみましょう。
varchar型のカラムvarchar_string、char型のカラムchar_string、text型のカラムtext_stringの3カラムを持ったテーブルです。
CREATE TABLE `employees`.`vchatest` ( `varchar_string` VARCHAR(8) NOT NULL , `char_string` CHAR(8) NOT NULL , `text_string` TEXT NOT NULL , PRIMARY KEY (`varchar_string`)) ENGINE = InnoDB;
テーブル構造はこのようになっています。
mysql> desc employees.vchatest; +----------------+------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +----------------+------------+------+-----+---------+-------+ | varchar_string | varchar(8) | NO | PRI | NULL | | | char_string | char(8) | NO | | NULL | | | text_string | text | NO | | NULL | | +----------------+------------+------+-----+---------+-------+
作成したテーブルvchatestに、末尾に半角の空白2個がついた文字列「STR 」をinsertします。
INSERT INTO `employees`.`vchatest` (`varchar_string`, `char_string`, `text_string`) VALUES ('STR ', 'STR ', 'STR ')
単純にselectしてみると、いずれも変わらないように見えます。
mysql> select * from vchatest; +----------------+-------------+-------------+ | varchar_string | char_string | text_string | +----------------+-------------+-------------+ | STR | STR | STR | +----------------+-------------+-------------+
concat関数を使って、末尾の空白がどうなっているかを確認してみましょう。
【関連記事】
▶MySQLの文字列結合にはCONCAT。GROUP_CONCATとGROUP BYで複数データ集約
mysql> select concat('"',varchar_string,'"'), concat('"',char_string,'"'), concat( '"',text_string,'"') from vchatest; +--------------------------------+-----------------------------+------------------------------+ | concat('"',varchar_string,'"') | concat('"',char_string,'"') | concat( '"',text_string,'"') | +--------------------------------+-----------------------------+------------------------------+ | "STR " | "STR" | "STR " | +--------------------------------+-----------------------------+------------------------------+
char型の場合は、挿入した文字列の末尾に追加した半角の空白が削除されてしまいました。
内部的に固定長でデータを保持するchar型では、最大文字長に足りない文を半角空白で埋めて保存し、selectで取り出す際に末尾の空白を全て削除します。
そのため、insert時に付加した末尾の空白が、select時にはなくなってしまうんですね。
末尾の空白を強制削除する処理を回避するのは困難なため、末尾に空白が入る可能性があるデータの場合はcharよりもvarcharを使うのが無難と言えるでしょう。
varchar使用時の注意点
MySQLのvarcharのサイズ指定は文字数?バイト数?
テーブルのカラムがvarchar(8)と定義されていた場合、8文字までデータinsertが可能でしょうか?それとも、8バイトなので半角なら8文字、全角なら4文字まで可能なのでしょうか?
試してみました。
まず、「あいうえおあいうえお」は、10文字で20バイトなので「データ長が長すぎる」という旨のエラーが出力されます。
mysql> INSERT INTO `employees`.`vchatest` (`varchar_string`, `char_string`, `text_string`) VALUES ('あいうえおあいうえお', 'x', 'x'); ERROR 1406 (22001): Data too long for column 'varchar_string' at row 1
次に、「あいうえおあいう」をinsertしてみましょう。
8文字で16バイトなので、varcharのサイズ指定が文字数ならinsert成功、バイト数なら上記と同様にエラーになるはずです。
mysql> INSERT INTO `employees`.`vchatest` (`varchar_string`, `char_string`, `text_string`) VALUES ('あいうえおあいう', 'x', 'x'); Query OK, 1 row affected (0.04 sec)
SQLの実行は成功しました。
全角8文字のデータが、varchar(8)に格納できました。
mysql> select * from vchatest; +-----------------+-------------+-------------+ | varchar_string | char_string | text_string | +-----------------+-------------+-------------+ | あいうえおあいう | x | x | | STR | STR | STR | +-----------------+-------------+-------------+
MySQLのvarchar型のサイズ指定は、文字数です。
MySQL4.1以前の古いMySQLでは、varcharのサイズ指定は文字数ではなく、バイト数でした。
varcharとtextの違い textはキーに指定することができない
varcharもtextも同じく文字列を扱うデータ型ですが、以下の違いがあります。
- text型は、テーブル作成の宣言時にサイズ指定が不要の可変型
- text型は、キーに指定することができない
- varchar型もtext型も65535文字まで格納可能
- 16,777,215文字格納できるMEDIUMTEXT型、4,294,967,295文字格納できるLONGTEXT型もあり
varcharの文字数宣言をなくしたものが、text型と考えておくと良いでしょう。
文字コードセットをutf8mb4に変更すると、varcharのインデックスが設定できないケースあり
utf8のデータベースを、utf8mb4に変更すると、varcharで設定できる文字の最大数が少なくなります。
MySQL :: MySQL 5.6 リファレンスマニュアル :: 10.1.11 以前の Unicode サポートから現在の Unicode サポートへのアップグレード
このため、今まで使えていたDDLがエラーになる可能性があるんですね。
ただし、MySQL5.7.9以降ではデフォルト設定値の調整が行われ、特に何もしなくてもエラーが回避できるようになっています。
MySQL(InnoDB) で charset を utf8mb4 にする注意点の現在 – DEV Community
MySQL5.7.8以前を使用していて、utf8mb4に変更する必要があり、MySQLのバージョンアップが可能なら検討するのが良いでしょう。
まとめ
- MySQLのvarcharとcharは末尾の空白の扱いで違いあり
- MySQLのvarcharのサイズ指定は、文字列長
- varcharと似た振る舞いをするtext型はキーに指定することはできない
- 古いMySQLでは、データベースをutf8mb4変換時に、varcharのインデックス設定で不具合の可能性あり