列已存在:修改列以在 Laravel 中具有唯一索引并进行迁移时为 1060

Column already exists: 1060 when modifying column to have a unique index in Laravel with migrations

今天我试图在我的 table 中为一个 slug 创建一个字符串列。我要求该列具有唯一索引,但 table 已经有信息,因此,在创建该列时,我收到一条错误消息,通知我新列中的重复值和空值。

public function up(){
  Schema::table( 'states', function( Blueprint $table ){
    $table->string( 'slug', 128 )->unique();
  } );
}

由于 slug 将包含 'name' 列的 slugified 版本,我决定分两步创建该列。首先,该列将成为常规列,我将循环遍历所有记录,使用 Str::slug() 创建正确的 slug 值。之后我打算修改列以在 Laravel's documentation:

之后添加 unique() 选项
public function up(){
  Schema::table( 'states', function( Blueprint $table ){
    $table->string( 'slug', 128 );
    $states = State::all();
    foreach( $states as $state ){
      $state->slug = Str::slug( $state->name );
      $state->save();
    }
    $table->string( 'slug', 128 )->unique()->change();
  } );
}

我认为这是一个很好的解决方案,因为我不会破坏数据库中的任何规则,因为所有名称都不同。我 运行 迁移,我得到了一个很好的错误:

SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'slug' (SQL: alter table `states` add `slug` varchar(128) not null)

关于如何正确创建迁移的任何想法?

换行:

$table->string( 'slug', 128 )->unique()->change();

$table->unique( 'slug' );

总计:

public function up(){
  Schema::table( 'states', function( Blueprint $table ){
    $table->string( 'slug', 128 );

    foreach( State::all() as $state ){
      $state->update(['slug' => = Str::slug( $state->name )]);
    }

    $table->unique( 'slug' );
  } );
}

https://laravel.com/docs/7.x/migrations#creating-indexes

这里有两个问题,一个是添加重复列并应用唯一索引,第二个可能是碰撞方法Str::slug

在添加列或唯一索引之前检查它是否不存在

public function up() {
    \DB::transaction(function() {
        if (!Schema::hasColumn('states', 'slug')) {
            Schema::table('states', function (Blueprint $table) {
                $table->string('slug', 128);
                $table->unique('slug', 'unique_slug_index');
            });
        }

        $states = State::all();
        foreach( $states as $state ){
            $state->slug = Str::slug( $state->name );
            $state->save();
        }
    });
}

\DB:transaction() clause automatically rollback your migration if it gets failed.

在尝试了#DigitalDrifter 的回答但没有成功之后(我一直收到同样的错误),我开始怀疑问题是否是我所有的列修改都是在同一个方法中执行的 function( Blueprint $table ) , 所以我决定把这个过程分成 3 个步骤:

public function up(){
  Schema::table( 'states', function( Blueprint $table ){
    $table->string( 'slug', 128 );
  } );

  $states = State::all();
  foreach( $states as $state ){
    $state->slug = Str::slug( $state->state );
    $state->save();
  }

  Schema::table( 'states', function( Blueprint $table ){
    $table->string( 'slug', 128 )->unique()->change();
  } );
}

我这个版本的代码是成功的,顺便说一句,#DigitalDrifter的建议也是正确的,我用我的方法测试了$table->unique( 'slug' );,它也有效。