OHTA412

Laravelのマイグレーションで、外部キー制約がエラーになるときの対策

Laravelのマイグレーションでテーブルを作成するとき、外部キー制約が原因でエラーになることがあります。原因はいろいろあるのですが、今回は型が違うことに起因するエラー対策です。

外部キー制約とは?
外部キー制約とは、テーブルのあるカラムに入れる値を、別のテーブルのあるカラムに存在する値しか許容しない制約のことです。
postsテーブルのuser_idカラムには、usersテーブルのidカラムに存在する値しか入れられないようにしたい場合などに使用します。user_idカラムはpostを投稿した投稿者IDを入れたいのですが、存在しないuserが投稿したことにできないようにします。

問題のあるコード

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        …
        $table->bigInteger('user_id');
        $table->foreign('user_id')->references('id')->on('users');
        …
    });
}

外部キー制約を設けた例です。

usersテーブルのidカラムに存在する値を、users_idカラムに入れようとしています。この状態でマイグレーションを実行すると「SQLSTATE[HY000]: General error: 1005 Can’t create table … (errno: 150 “Foreign key constraint is incorrectly formed”)」というようなエラーが返ってきます。「外部キー制約が正しくない」と言われています。

改善を加えたコード

public function up()
{
    Schema::create('posts', function (Blueprint $table) {
        …
        $table->unsignedBigInteger('user_id'); // bigIntegerをunsignedBigIntegerに変更
        $table->foreign('user_id')->references('id')->on('users');
        …
    });
}

usersテーブルのidはbigIncrements(‘id’)で定義されています。bigIncrementsは「符号なしのBIGINTを使用した自動増分ID」です。符号なしなので、マイナスの値は対応していません。そのため、bigIntegerでuser_idを定義するとマイナス値まで許容することになり、型が一致せずエラーになります。ちなみに、BIGINTとはINT(integer)より多くの桁数まで対応した数字です。

5行目のように、bigIntegerをunsignedBigIntegerに変更すれば解決できます。unsignedとは「符号なし」という意味なので、これにより型が一致します。