Laravelで既存のテーブルに外部キー制約を追加・削除する方法

暇なときに予定を探せるアプリ[yoteiPicker](https://yoteipicker.com/)をリリースしました。

この記事では、Laravelのマイグレーションですでにあるテーブルに外部キー制約を追加する方法を解説します。

Laravelのバージョンは6系です。
mysqlのバージョンは5.7系です。

[＞＞フリーランスも対象！エンジニア転職におすすめなサイト5選](https://www.kamome-susume.com/enginner-job-change-site/
)

以下のようなテーブルがあったとします。

booksテーブル
book_id
book_name

categoriesテーブル
category_id
category_name

すでにどちらのマイグレーションも実行済みだけど、booksテーブルにcategory_idと外部キー制約を追加したいってときに使える記事です。

【完成系】
booksテーブル
book_id
book_name
category_id(外部キー制約)

まずはカラム追加のマイグレーションファイルを作成します。

```
php artisan make:migration add_category_id_to_books_table --table=books
```

マイグレーションファイルを編集します。

```php
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddCategoryIdToBooksTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('books', function (Blueprint $table) {
            // カラム追加
            $table->bigInteger('category_id')->unsigned()->after('book_name');
            // カラムの外部キー制約追加
            $table->foreign('category_id')->references('category_id')->on('categories')->OnDelete('cascade');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('books', function (Blueprint $table) {
            // 外部キー制約の削除
            $table->dropForeign('books_category_id_foreign');
            // カラムの削除
            $table->dropColumn('category_id');
        });
    }
}
```

マイグレーションを実行します。

```
php artisan migrate
```

これで、外部キー制約のカラムを追加できました。
![スクリーンショット 2021-08-04 21.35.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1693248/273ca470-0ddd-1376-1ee7-91980abd8a8a.png)

##　解説

```
$table->bigInteger('category_id')->unsigned()->after('book_name');
```

`bigInteger('category_id')`はcategoriesテーブルのcategory_idと型を合わせる必要があります。

categoriesテーブル
category_id
category_name

マイグレーションファイルでは、デフォルトで以下のように作成されるからです。

```
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}
```


categoriesテーブルのcategory_idはbigIncrementsなので、bigIntegerにしているってわけですね。

laravel5.8以前の場合は、categoriesテーブルのcategory_idはincrementsで作成されるでしょう。その場合は、integer('category_id')にする必要があります。

`unsigned()->after('book_name')`のunsigned()は符号なし、つまりマイナスの数字は許容しない、'after('book_name')'でbook_nameカラムの後にcategory_idカラムが追加されるように指定しています。

まとめると、

```
$table->bigInteger('category_id')->unsigned()->after('book_name');
```

category_idのカラムの型はbigIntegerで符号なし、book_nameカラムの後にcategory_idカラムを追加って意味です。

```
$table->foreign('category_id')->references('category_id')->on('categories')->OnDelete('cascade');
```

```
foreign('category_id')->references('category_id')->on('categories')
```

外部キーはcategory_idで、参照するのはcategoriesテーブルのcategory_idだよって意味です。

`OnDelete('cascade')`は決まり文句みたいなもので、
外部キー制約を CASCADE に設定することで、紐づいているレコードも含め一括で削除可能です。

```
            // 外部キー制約の削除
            $table->dropForeign('books_category_id_foreign');
            // カラムの削除
            $table->dropColumn('category_id');
```

downにはrollbackした時の操作を書きます。
`dropForeign('books_category_id_foreign')`この部分ですが、
外部キーを追加するテーブル名_外部キー名_foreignとしてください。

downに外部キー制約の削除とカラムの削除を書かないと、rollbackできずにマイグレーションエラーとなりますので、ご注意を。

他にも記事書いているので、ぜひプロフィールからご参照ください。
・マイグレーション
・クエリビルダなど
書いています。

##既存テーブルから外部キー制約の削除
すでに外部キー制約のカラムがあるテーブルから外部キー制約のカラムを削除したいと思います。

まずはマイグレーションファイルを作成。

```
php artisan make:migration drop_category_id_to_books_table --table=books
```

マイグレーションファイルの編集
upに外部キー制約削除をdownにはrollbackしたときに元に戻す処理を書きます。

```php
    public function up()
    {
        Schema::table('books', function (Blueprint $table) {
            // 外部キー制約の削除
            $table->dropForeign('books_category_id_foreign');
            // カラム削除
            $table->dropColumn('category_id');
        });
    }

```

```php
    public function down()
    {
        Schema::table('books', function (Blueprint $table) {
            // カラムの追加
            $table->unsignedBigInteger('category_id')->after('user_id');
            // 外部キーの追加
            $table->foreign('category_id')->references('category_id')->on('categories');
        });
    }
```

##既存テーブルからカラムは削除したくないけど外部キー制約は解除したい場合
マイグレーションファイルを作成
`php artisan make:migration drop_foreign_key_to_books_table --table=books`

マイグレーションファイルを編集

```php
    public function up()
    {
        Schema::table('books', function (Blueprint $table) {
            // 外部キー制約の削除
            $table->dropForeign('books_category_id_foreign');
        });
    }

```

```php
    public function down()
    {
        Schema::table('books', function (Blueprint $table) {
            // 外部キーの追加
            $table->foreign('category_id')->references('category_id')->on('categories');
        });
    }
```
データベースを確認すると、外部キー名などが残ってしまいます。その場合は、以下のSQLを実行すれば外部キー名なども消えます。

データベースでSQLを実行

```
alter table books
 drop index books_category_id_foreign
```

暇なときに予定を探せるアプリ[yoteiPicker](https://yoteipicker.com/)をリリースしました。

[＞＞Laravelのマイグレーションが怖くない【作成・カラムの追加・削除】](https://qiita.com/kamome_susume/items/22fe17935bbd1760b7f7
)
[＞＞【Laravelクエリビルダ】複数のカラムをgroupByでグループ化させる
](https://qiita.com/kamome_susume/items/29a29c65356de9a0a272
)

[＞＞フリーランスも対象！エンジニア転職におすすめなサイト5選](https://www.kamome-susume.com/enginner-job-change-site/
)