Laravelで後から複数カラムにUNIQUE制約を追加する

migration作成

php artisan make:migration add_unique_constraints_to_post_records_table --table="post_records"

すると、以下のようなmigrationファイルができるので編集する。

/Users/w/workspace/t/approot/database/migrations/2018_07_08_190530_add_unique_constraints_to_post_records_table.php
<?php

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

class AddUniqueConstraintsToPostRecordsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('post_records', function (Blueprint $table) {
            $table->unique(['plan_id', 'id_str']);
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    
        Schema::table('post_records', function (Blueprint $table) {
            $table->dropUnique(['plan_id', 'id_str']);
        });
    }
}

migration実行

php artisan migrate

とすると

Illuminate\Database\QueryException  : SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'PID-5B2-284-C16-2B5-5-1011252678360379399' for key 'post_records_plan_id_id_str_unique' (SQL: alter table `post_records` add unique `post_records_plan_id_id_str_unique`(`plan_id`, `id_str`))

となって怒られる。

alter table `post_records` add unique `post_records_plan_id_id_str_unique`(`plan_id`, `id_str`)

というSQLを発行し、既存のデータに重複が存在しているのでエラーになっている。 なので、既存のテーブルからなんとかして重複を排除する。 今回の場合、.envでDB情報を確認して、
1. 既存データベースの保存

/Applications/MAMP/Library/bin/mysqldump -u foo -p -B db > /Users/w/db_dump.sql
  1. 不要データの削除
/Applications/MAMP/Library/bin/mysql -u foo -p
USE db;
TRUNCATE TABLE post_records;

として、重複データを削除する。 TRUNCATEは厳密にはテーブルをDROPして作り直す。

重複ならインサートしない

ってことにしたいので、INSERTする部分をtry, catchで囲む。

try {
    $pr->save();
} catch (\Exception $e) {
    /** Do nothing */
}

とかする。

教訓

最初のdb設計の段階でunique制約をしっかり指定すべし!