How do I reverse a unique key added on multiple columns in Laravel? Basically, what should go in the down() function of this migration code:
public function up()
{
Schema::table('topics', function($table)
{
$table->unique(array('subject_id', 'grade_id', 'semester_id', 'name'));
}
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('topics', function($table)
{
}
}
To drop a unique index, you use dropUnique('name_of_index').
If you're not specifying an index name in the second parameter of unique(), the name of the index will be tableName_fieldsSeperatedByUnderscore_unique.
public function down()
{
Schema::table('topics', function($table)
{
$table->dropUnique('topics_subject_id_grade_id_semester_id_name_unique');
}
}
There are two approaches to drop unique index :
First Approach :
In dropUnique() function we can pass array so that you don't need to use exact unique index name like "tableName_fieldsSeperatedByUnderscore_unique". Here is code snippet
Schema::table('users', function (Blueprint $table) {
$table->dropUnique(['email']);
});
This will drop the unique index of column 'email'.
Second Approach:
This approach is exactly same as described by Marwelln,still I would like to put it here again. You can pass unique index name in the dropUnique(), it will also work. But be sure that you are confident about unique index name.Code for that looks like this:
Schema::table('users', function (Blueprint $table) {
$table->dropUnique('users_email_unique');
});
Related
I'm trying to test a migration rollback after changing a column type and setting the index.
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex('attachment_id');
$table->text('attachment_id')->nullable()->change();
});
}
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::table('attachments', function(Blueprint $table) {
$table->unsignedBigInteger('attachment_id')->nullable()->change();
$table->index('attachment_id');
});
}
The migration runs fine and assigns the index. But when I run the rollback I run into the following error:
SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT column 'attachment_id' used in key specification without a key length (SQL: ALTER TABLE attachments CHANGE attachment_id attachment_id TEXT DEFAULT NULL)
This table was originally set up incorrectly (without an index and without the correct column type). I'm trying to update this but I also want to make sure if any issues occur in production due to the change it can be rolled back quickly.
How are you meant to get around this? The index is already meant to be dropped?
I've tried changing the order of operations and also running separate Schema functions. Also tried changing it to a string instead of text with a set length and no luck.
The below doesn't work:
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex('attachment_id');
});
Schema::table('attachments', function(Blueprint $table) {
$table->string('attachment_id', 255)->change();
});
}
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex('attachment_id');
$table->string('attachment_id', 255)->change();
});
}
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->string('attachment_id', 255)->change();
$table->dropIndex('attachment_id');
});
}
Well apparently I missed something because putting the dropIndex inside an array worked.
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('attachments', function(Blueprint $table) {
$table->dropIndex(['attachment_id']);
});
Schema::table('attachments', function(Blueprint $table) {
$table->string('attachment_id', 255)->change();
});
}
Answer found here:
https://github.com/laravel/framework/issues/20501#issuecomment-321814806
That's because your the name of your index is test_table_user_id_index in this case. That happens in the createIndexName method in Blueprint.php:
$index = strtolower($this->table.''.implode('', $columns).'_'.$type);
When you pass a string as a parameter, the method will not convert it to a name. Only when you pass an array:
protected function dropIndexCommand($command, $type, $index)
{
$columns = [];
// If the given "index" is actually an array of columns, the developer means
// to drop an index merely by specifying the columns involved without the
// conventional name, so we will build the index name from the columns.
if (is_array($index)) {
$index = $this->createIndexName($type, $columns = $index);
}
return $this->indexCommand($command, $columns, $index);
}
I have a migration which creates users, now I would like to add that migration and give each new user a unique random value from my array. So far the values are random but not unique, how can I do that?
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->string('theme_color')->default($this->generateColor())
->after('password')
->unique();
});
}
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('theme_color');
});
}
public function generateColor()
{
$colors = [
'#94A3B8',
'#64748B',
'#F87171',
'#EA580C',
'#FDE68A',
'#713F12',
'#A3E635',
'#4ADE80',
'#A7F3D0',
'#99F6E4',
'#22D3EE',
'#0284C7',
'#2563EB',
'#8B5CF6',
'#D946EF',
'#9D174D',
'#F43F5E'
];
$k = array_rand($colors);
return $colors[$k];
}
Migration runs only once. So, you cannot set different values there, What your migration will do is it will set one random value as default forever.
To achieve this use Eloquent: Mutators & Casting (setter method) in the Laravel model, check the documentation https://laravel.com/docs/8.x/eloquent-mutators#defining-a-mutator
my code below is working fine. Problem is when i got data in database which is null in user_id field. Migration rollback will not pass successfully. What is good approach to solve this problem?
Should i change every null in column user_id to empty string before i change nullable to false in rollback?
public function up()
{
Schema::table('classes', function (Blueprint $table) {
$table->text('user_id')->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('classes', function (Blueprint $table) {
$table->text('user_id')->nullable(false)->change();
});
}
This problem has been seem before, I couldn't find other solution than update the values to empty string before changing the column, the database engine will always complaint.
Updated:
You could do this like this and should work:
use Illuminate\Support\Facades\DB;
/*
*
* Some code
*
*/
public function up()
{
DB::table('classes')->whereNull('user_id')->update(['user_id'=>'']);
Schema::table('classes', function (Blueprint $table) {
$table->text('user_id')->nullable()->change();
});
}
I've created the database migration below. What I'd like to do is create an accounts table with an id as a primary key. However, I don't want the key to autoincrement starting at 1. Rather, I'd like it to autoincrement starting at 800500.
Is there a way to set the default value of a primary key like this?
I'm currently using Laravel v4.2.11 and sqlite v3.8.3.
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAccountsTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('accounts', function(Blueprint $table)
{
$table->increments('id')->unsigned()->default(800500);
$table->string('name', 100);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('accounts');
}
}
The default method in the schema builder
Declare(s) a default value for a column
If you need the increment to start at a given value take a look at this answer.
You'd add the query to the migration:
public function up()
{
Schema::create('accounts', function(Blueprint $table)
{
$table->increments('id');
$table->string('name', 100);
$table->timestamps();
});
DB::statement("UPDATE SQLITE_SEQUENCE SET seq = 800500 WHERE name = 'accounts'");
}
There is no 'laravel' way to do this.
How can I set a unique constraints on two columns?
class MyModel extends Migration {
public function up()
{
Schema::create('storage_trackers', function(Blueprint $table) {
$table->increments('id');
$table->string('mytext');
$table->unsignedInteger('user_id');
$table->engine = 'InnoDB';
$table->unique('mytext', 'user_id');
});
}
}
MyMode::create(array('mytext' => 'test', 'user_id' => 1);
// this fails??
MyMode::create(array('mytext' => 'test', 'user_id' => 2);
The second param is to manually set the name of the unique index. Use an array as the first param to create a unique key across multiple columns.
$table->unique(array('mytext', 'user_id'));
or (a little neater)
$table->unique(['mytext', 'user_id']);
Simply you can use
$table->primary(['first', 'second']);
Reference: http://laravel.com/docs/master/migrations#creating-indexes
As an example:
Schema::create('posts_tags', function (Blueprint $table) {
$table->integer('post_id')->unsigned();
$table->integer('tag_id')->unsigned();
$table->foreign('post_id')->references('id')->on('posts');
$table->foreign('tag_id')->references('id')->on('tags');
$table->primary(['post_id', 'tag_id']);
});
If you have a default unique index with one column and you will change it with two columns, or create a new one with two columns, this script will do that for you:
public function up()
{
Schema::table('user_plans', function (Blueprint $table) {
$table->unique(["email", "plan_id"], 'user_plan_unique');
});
}
public function down()
{
Schema::table('user_plans', function (Blueprint $table) {
$table->dropUnique('user_plan_unique');
});
}
DB::statement("ALTER TABLE `project_majr_actvities`
ADD UNIQUE `unique_index`(`activity_sr_no`, `project_id`)");