tanamonの稀に良く書く日記

KEEP CALM AND DRINK BEER

MySQLでtimestampに桁数指定をする時にはcurrent_timestampにも桁数を付ける

今日、ハマったこと。

こんなテーブルがあったとする。

mysql> create table test(
    ->   id int unsigned not null auto_increment,
    ->   name varchar(100) not null,
    ->   last_modified timestamp not null default current_timestamp on update current_timestamp,
    ->   primary key (id)
    -> );
Query OK, 0 rows affected (0.01 sec)

mysql> insert into test(name) values('name1');
Query OK, 1 row affected (0.00 sec)

mysql> select * from test;
+----+-------+---------------------+
| id | name  | last_modified       |
+----+-------+---------------------+
|  1 | name1 | 2019-07-02 22:54:52 |
+----+-------+---------------------+
1 row in set (0.00 sec)

ここで、last_modifiedをミリ秒以下の精度で持たせたくなったとする。

timestamp型にミリ秒以下を持たせたい場合はtimestamp(n)として、nに持たせたい桁数を渡せばいいらしい。 ミリ秒ならtimestamp(3)、マイクロ秒ならtimestamp(6)とすればよいようだ。 マイクロ秒にしてみる。

mysql> alter table test modify last_modified timestamp(6) not null default current_timestamp on update current_timestamp;
ERROR 1067 (42000): Invalid default value for 'last_modified'

しかしエラーになった。default valueがおかしいらしい。

ここで、元のテーブルがもっとややこしかったせいで原因特定までだいぶ遠回りしたけど、結論を書くとcurrent_timestampにも桁数が必要だった。

mysql> alter table test modify last_modified timestamp(6) not null default current_timestamp(6) on update current_timestamp(6);
Query OK, 1 row affected (0.04 sec)
Records: 1  Duplicates: 0  Warnings: 0

これが正しい。

ちなみに、公式ドキュメントにもちゃんと書いてあった。

TIMESTAMP または DATETIME カラム定義のいずれかの場所に明示的な小数秒精度値が含まれる場合、カラム定義全体で同じ値を使用する必要があります。次の場合は許可されます。

CREATE TABLE t1 ( ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) );

次の場合は許可されません。

CREATE TABLE t1 ( ts TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP(3) );

MySQL :: MySQL 5.6 リファレンスマニュアル :: 11.3.5 TIMESTAMP および DATETIME の自動初期化および更新機能

ドキュメントはちゃんと読もうと思った。