LoginSignup
12
5

More than 3 years have passed since last update.

primary key のカラムとは別に auto_incremen するカラムがあるテーブルを migrate したい

Last updated at Posted at 2020-06-14

前提

  • 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`)

なんか counterprimary key がついてる!!

そうなんです。
auto_increment を有効にすると自動で primary key がついてきてしまうんです。
実際に sql 文を構築しているクラスを読みに行くと、確かにそう書いてあるのだ。
Laravel migration core
なんてこった。
たしかに mysql の仕様では auto_increment のカラムには index 貼れとあるが、勝手に primary key に勝手にされたら困るんだなぁ。
実際には auto_increment = primary key というケースがほとんどなんだろうけど、明示的に primary key にするメソッドがあるんだからさぁ。

解決策

いくつか対応パターンを考えた。
1. UUID を諦める
2. UUID は利用するが primary key は number に譲って、モデルなどの運用でカバー
3. 生の SQL を書く
4. migration ファイルで頑張る
5. このクラスをオーバーライドする方法を探して、 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
});

やってること

  1. id のカラムから primary() のメソッドを削除
  2. counterunique を付与
  3. primary key を削除
  4. idprimary 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) を使い続けるので、またこれに出くわすかもしれないので防備しておく。

12
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
5