⛓️
primary key のカラムとは別に auto_increment するカラムがあるテーブルを migrate したい
前提
- DB の主キーは連番ではない
- 連番のカラムが必要
- Laravel Framework 5.8.36
- mysql Ver 14.14 Distrib 5.7.25
実行しようとした migration ファイル
Schema::create('tests', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->bigIncrements('counter');
$table->timestamps();
});
出たエラー
SQLSTATE[42000]: Syntax error or access violation: 1068 Multiple primary key defined (SQL: alter table `tests` add primary key `tests_id_primary`(`id`))
「複数の primary key
は設定できないぞ」って感じのメッセージである。
どうみても主キー1個だろ?と思ったが、何か隠された仕様があるのかもしれないと思い、 php artisan migrate --pretend
を実行してみると。
create table `tests` (
`id` char(36) not null,
`counter` bigint unsigned not null auto_increment primary key,
`created_at` timestamp null,
`updated_at` timestamp null
) default character set utf8mb4 collate 'utf8mb4_unicode_ci'
alter table `tests` add primary key `posts_id_primary`(`id`)
なんか counter
に primary key
がついてる!!
そうなんです。
auto_increment
を有効にすると自動で primary key
がついてきてしまうんです。
実際に sql 文を構築しているクラスを読みに行くと、確かにそう書いてあるのだ。
なんてこった。
たしかに mysql の仕様では auto_increment
のカラムには index
貼れとあるが、勝手に primary key
に勝手にされたら困るんだなぁ。
実際には auto_increment
= primary key
というケースがほとんどなんだろうけど、明示的に primary key
にするメソッドがあるんだからさぁ。
解決策
いくつか対応パターンを考えた。
- UUID を諦める
- UUID は利用するが primary key は number に譲って、モデルなどの運用でカバー
- 生の SQL を書く
- migration ファイルで頑張る
- このクラスをオーバーライドする方法を探して、 primary key つけないようにする
今回は 4 を採用した。
修正した migration ファイル
Schema::create('tests', function (Blueprint $table) {
$table->uuid('id'); // 1
$table->bigIncrements('counter');
$table->timestamps();
$table->unique('counter'); // 2
$table->dropPrimary(); // 3
$table->primary('id'); // 4
});
やってること
-
id
のカラムからprimary()
のメソッドを削除 -
counter
にunique
を付与 -
primary key
を削除 -
id
をprimary key
に指定
確認
mysql> desc tests;
+-------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------------+------+-----+---------+----------------+
| id | char(36) | NO | PRI | NULL | |
| counter | bigint(20) unsigned | NO | UNI | NULL | auto_increment |
| created_at | timestamp | YES | | NULL | |
| updated_at | timestamp | YES | | NULL | |
+-------------------+---------------------+------+-----+---------+----------------+
おつかれさまでした
なかなかこんな変なことする人はいないと思うけれども、宗教上の理由で自分は uuid(ulid) を使い続けるので、またこれに出くわすかもしれないので防備しておく。
Discussion