LoginSignup
42
21

More than 3 years have passed since last update.

laravelのmigrationでintのカラムが勝手にAutoIncrementにされてハマった話

Last updated at Posted at 2019-10-28

laravel: 5.7.28
Mysql: 5.7

先に結論

migrationを書くときには引数に気をつけよう!!

何があったの

新しいテーブルを作成するため、このようなmigrationファイルを作成し実行したところエラーが出た。

2019_10_28_000000_create_m_conf.php
class CreateMConf extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('m_conf', function (Blueprint $table) {
            $table->increments('id')->unsigned()->nullable(false);
            $table->tinyInteger('type')->unsigned()->nullable(false)->default(1);
            $table->integer('watcher_id', 10)->nullable(false);
            $table->string('content', 200)->nullable(false);
            $table->char('created_from', 36)->nullable(false);
            $table->timestamps();
        });
    }

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

出力されたエラー

$ php artisan migrate
Migrating: 2019_10_28_000000_create_m_conf

   Illuminate\Database\QueryException  : SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a key (SQL: create table `m_conf` (`id` int unsigned not null auto_increment primary key, `type` tinyint unsigned not null default '1', `watcher_id` int not null auto_increment primary key, `content` varchar(200) not null, `created_from` char(36) not null, `created_at` timestamp null, `updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci')

  at /var/www/witone-prjct01/vendor/laravel/framework/src/Illuminate/Database/Connection.php:664
    660|         // If an exception occurs when attempting to run a query, we'll format the error
    661|         // message to include the bindings with SQL, which will make this exception a
    662|         // lot more helpful to the developer instead of just the database's errors.
    663|         catch (Exception $e) {
  > 664|             throw new QueryException(
    665|                 $query, $this->prepareBindings($bindings), $e
    666|             );
    667|         }
    668|

  Exception trace:

  1   Doctrine\DBAL\Driver\PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a key")
      /var/www/witone-prjct01/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:119

  2   PDOException::("SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a key")
      /var/www/witone-prjct01/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117

  Please use the argument -v to see more details.

どうやら、AutoIncrementを複数のカラムに設定しているということでエラーが出ているらしい。
が、AutoIncrementはidカラムにしか設定していないはず・・・。

改めて、まずは実行されているCREATE文を確認。

php artisan migrate --pretendで実行するSQLが確認できる。

CreateMConf: create table `m_conf`
     (`id` int unsigned not null auto_increment primary key,
      `type` tinyint unsigned not null default '1', 
      `watcher_id` int not null auto_increment primary key, 
      `content` varchar(200) not null, 
      `created_from` char(36) not null, 
      `created_at` timestamp null,
      `updated_at` timestamp null
      )
default character set utf8mb4 collate 'utf8mb4_unicode_ci'

やはり、エラー文の通りwatcher_idにもAutoIncrementが設定されてしまっている。
しかし、どこをどう見てもmigrationファイルでwatcher_idにはincrementsではなくintegerを設定している。

試しに、カラム名を変更したりnullable()を消したりして、新しいファイルの内容がキャッシュか何かで反映されていないのかも?と確認するも
エラー内容SQLSTATE[42000]: Syntax error or access violation: 1075 Incorrect table definition; there can be only one auto column and it must be defined as a keyに変化なし。

migrationがなにやってるか調べた

laravel公式リファレンスにもmigrationについてあまり詳しく書いてない。
仕方ないので、migrationでintegerカラムを設定するとき内部的にどんな処理をいているのか見てみることにした。
以下、該当箇所のみ抜粋。

\vendor\laravel\framework\src\Illuminate\Database\Schema\Blueprint.php
    /**
     * Create a new integer (4-byte) column on the table.
     *
     * @param  string  $column
     * @param  bool  $autoIncrement
     * @param  bool  $unsigned
     * @return \Illuminate\Database\Schema\ColumnDefinition
     */
    public function integer($column, $autoIncrement = false, $unsigned = false)
    {
        return $this->addColumn('integer', $column, compact('autoIncrement', 'unsigned'));
    }

なんと、integer()の第2引数はAutoIncrementかどうかを判断するものだった!!!
しかも第3引数はunsignedを判断するものであることも判明!
てっきり、string()char()などの第2引数と同じく長さを設定できると勘違いをしていました。。。

修正したあとのSQL

CreateMConf: create table `m_conf`
     (`id` int unsigned not null auto_increment primary key,
      `type` tinyint unsigned not null default '1', 
      `watcher_id` int not null, 
      `content` varchar(200) not null, 
      `created_from` char(36) not null, 
      `created_at` timestamp null,
      `updated_at` timestamp null
      )
default character set utf8mb4 collate 'utf8mb4_unicode_ci'

ということで、無事にmigrationを実行することができました。

反省

  • migrationが内部的にどんな処理をしているのか見るまでにとても時間がかかった
    • 実際には、色々いじっていく中で同僚が第2変数を削除するとうまくいくことを発見したのが先だった
    • 確実な情報を見ないで「こうやって書けばこんな感じで動くはず!」という思い込みが激しかった
    • vendorの中身をみるのがちょっと怖かった

とはいえ、同じような事象で困ったという記事が見つからなかったので
同じような事象で困ってしまった人には参考になる記事が書けたかなと思います。

42
21
0

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
42
21