Today I was trying to create a string column for a slug in one of my tables. I required the column to have a unique index, but the table had information already, so, the moment the column was created, I got an error message informing me of duplicate and empty values in the new column.
public function up(){
Schema::table( 'states', function( Blueprint $table ){
$table->string( 'slug', 128 )->unique();
} );
}
Since the slug was going to contain the slugified version of the 'name' column, I decided to create the column in two steps. First the column was going to be a regular column and I was going to cycle through all the records creating the correct slug value using Str::slug(). After that I was going to modify the column to add the unique() option following Laravel's documentation :
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();
} );
}
I was thinking this was a fine solution, because I was not going to break any rules in my database since all the names were different. I ran the migration and I got a nice error:
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'slug' (SQL: alter table `states` add `slug` varchar(128) not null)
Any ideas on how can I create correctly the migration?
Change the line:
$table->string( 'slug', 128 )->unique()->change();
to
$table->unique( 'slug' );
All together:
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' );
} );
}
See https://laravel.com/docs/7.x/migrations#creating-indexes .
After trying # DigitalDrifter 's answer without success (I kept getting the same error), I started wondering if the problem was that all my column modifications were executed inside the same method function( Blueprint $table )
, so I decided to separate the process into 3 steps like this:
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();
} );
}
This version of my code was successful, by the way, # DigitalDrifter 's suggestion was also correct, I tested $table->unique( 'slug' );
with my approach and it also works.
There are two problems here, one is adding a duplicate column and applying unique index and second is possibly the collision in method Str::slug
before adding column or unique index check if it doesn't exist already
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.