今天,我试图在我的一张表中为一个子弹创建一个字符串列。我要求该列具有唯一索引,但是该表已经具有信息,因此,在创建该列的那一刻,我收到一条错误消息,通知我新列中的重复值和空值。
public function up(){
Schema::table( 'states', function( Blueprint $table ){
$table->string( 'slug', 128 )->unique();
} );
}
由于该段将包含'name'列的段化版本,所以我决定分两步创建该列。首先,该列将成为常规列,我将遍历所有记录,使用Str :: 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。
尝试#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' );
,它也有效。
这里有两个问题,一个是添加重复的列并应用唯一索引,第二个可能是方法Str :: slug中的collision
在添加列或唯一索引之前,检查是否还不存在
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()
子句会自动回滚您的迁移(如果它失败。