【MySQL】整数型の表示幅、、、消えてる!?

恥ずかしながら「整数型の表示幅消えてるやん！」ということに今更気づいたので、簡単に調べてまとめておきました。

# 表示幅とは
`INT(11)`のような表記で見かける「(11)」の部分、これが「表示幅」と呼ばれるものです。これと、例えば`VARCHAR(255)`のような文字列型の定義とは異なり、実際のデータが格納される桁数を指定しているわけではありません。

では、`INT(4)`と指定したら、すべての値が4桁で表示されるのかというとそうではなく、表示幅が反映されるのは、`ZEROFILL`（ゼロ埋め）の設定がされている場合だけです。
`ZEROFILL`が有効な場合は指定された桁数未満の数字は0で埋められますが、`ZEROFILL`の指定がない場合はほとんど意味がありません。
この紛らわしい見た目から、表示幅がデータ長の制約と勘違いしたことがある人も多いはずです。

この表示幅は、MySQL8.0.17以降では非推奨となり、8.0.19以降では一部の例外を除いて指定が無視されるようになりました。この変更は、`INT`だけでなく、`BIGINT`や`SMALLINT`など他の整数型にも共通しています。

# 実際の挙動
### MySQL8.0.16以前
まず、8.0.16以前のバージョンでの表示幅の挙動を確認してみます。
``` sql
mysql> CREATE TABLE `sample` (
    ->     `default_int_column` int(11) NOT NULL  AUTO_INCREMENT,
    ->     `zerofill_int_column` int(4) zerofill NOT NULL,
    ->     `not_zerofill_int_column` int(4) NOT NULL,
    ->     PRIMARY KEY (`default_int_column`)
    -> );
Query OK, 0 rows affected (0.11 sec)

mysql> DESC sample;
+-------------------------+--------------------------+------+-----+---------+----------------+
| Field                   | Type                     | Null | Key | Default | Extra          |
+-------------------------+--------------------------+------+-----+---------+----------------+
| default_int_column      | int(11)                  | NO   | PRI | NULL    | auto_increment |
| zerofill_int_column     | int(4) unsigned zerofill | NO   |     | NULL    |                |
| not_zerofill_int_column | int(4)                   | NO   |     | NULL    |                |
+-------------------------+--------------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)

mysql> INSERT INTO `sample` VALUES (12, 12, 12);
Query OK, 1 row affected (0.04 sec)

mysql> INSERT INTO `sample` VALUES (1234567, 1234567, 1234567);
Query OK, 1 row affected (0.08 sec)

mysql> select * FROM `sample`;
+--------------------+---------------------+-------------------------+
| default_int_column | zerofill_int_column | not_zerofill_int_column |
+--------------------+---------------------+-------------------------+
|                 12 |                0012 |                      12 |
|            1234567 |             1234567 |                 1234567 |
+--------------------+---------------------+-------------------------+
2 rows in set (0.01 sec)
```
このように、`ZEROFILL`が有効な場合のみ、指定された表示桁数に達するまで0埋めされることがわかります。一方で、INT(4)という表示幅の指定があっても、5桁以上の数字をそのまま保存でき、表示幅によって桁数が強制的に制限されるわけではありません。

### MySQL8.0.17
次に表示幅の指定が非推奨となった8.0.17の挙動を見ていきます。
``` sql
mysql> CREATE TABLE `sample` (
    ->     `default_int_column` int(11) NOT NULL  AUTO_INCREMENT,
    ->     `zerofill_int_column` int(4) zerofill NOT NULL,
    ->     `not_zerofill_int_column` int(4) NOT NULL,
    ->     PRIMARY KEY (`default_int_column`)
    -> );
Query OK, 0 rows affected, 4 warnings (0.02 sec)

mysql> SHOW WARNINGS;
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Level   | Code | Message                                                                                                                                                                   |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Warning | 1681 | Integer display width is deprecated and will be removed in a future release.                                                                                              |
| Warning | 1681 | The ZEROFILL attribute is deprecated and will be removed in a future release. Use the LPAD function to zero-pad numbers, or store the formatted numbers in a CHAR column. |
| Warning | 1681 | Integer display width is deprecated and will be removed in a future release.                                                                                              |
| Warning | 1681 | Integer display width is deprecated and will be removed in a future release.                                                                                              |
+---------+------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
4 rows in set (0.00 sec)

mysql> DESC sample;
+-------------------------+--------------------------+------+-----+---------+----------------+
| Field                   | Type                     | Null | Key | Default | Extra          |
+-------------------------+--------------------------+------+-----+---------+----------------+
| default_int_column      | int(11)                  | NO   | PRI | NULL    | auto_increment |
| zerofill_int_column     | int(4) unsigned zerofill | NO   |     | NULL    |                |
| not_zerofill_int_column | int(4)                   | NO   |     | NULL    |                |
+-------------------------+--------------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
```
表示幅と`ZEROFILL`が非推奨であるという警告が出ていますが、表示幅の指定自体はまだ有効です。

### MySQL8.0.19以降
最後に、MySQL 8.0.19以降での挙動を確認します。
``` sql
mysql> CREATE TABLE `sample` (
    ->     `default_int_column` int(11) NOT NULL  AUTO_INCREMENT,
    ->     `zerofill_int_column` int(4) zerofill NOT NULL,
    ->     `not_zerofill_int_column` int(4) NOT NULL,
    ->     PRIMARY KEY (`default_int_column`)
    -> );
Query OK, 0 rows affected, 4 warnings (0.01 sec)

mysql> DESC sample;
+-------------------------+--------------------------+------+-----+---------+----------------+
| Field                   | Type                     | Null | Key | Default | Extra          |
+-------------------------+--------------------------+------+-----+---------+----------------+
| default_int_column      | int                      | NO   | PRI | NULL    | auto_increment |
| zerofill_int_column     | int(4) unsigned zerofill | NO   |     | NULL    |                |
| not_zerofill_int_column | int                      | NO   |     | NULL    |                |
+-------------------------+--------------------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
```
MySQL8.0.19以降は`ZEROFILL`属性が付いている列と`TINYINT(1)`を除いて表示幅の指定が完全に無視されるようになっています。
[MySQL 8.0.19リリースノート](https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-19.html#:~:text=Display%20width%20specification%20for%20integer%20data%20types%20was%20deprecated%20in%20MySQL%208.0.17%2C%20and%20now%20statements%20that%20include%20data%20type%20definitions%20in%20their%20output%20no%20longer%20show%20the%20display%20width%20for%20integer%20types%2C%20with%20these%20exceptions%3A)  

# まとめ
整数型の表示幅は、MySQL8.0.17から非推奨となり、8.0.19以降では一部を除いて無視されるようになりました。`ZEROFILL`も非推奨になっているので、データの見た目を制御したい場合は、`LPAD()`関数などで対応しましょう。

# 参考
[MySQL :: MySQL Documentation](https://dev.mysql.com/doc/)