How to migration change columns type? - laravel

I got an error, When I try to column type from string to text, With migration function of Laravel.
File : {data_time}_change_db_structure.php
public function up()
{
Schema::table('service_request_type', function (Blueprint $table) {
$table->dropIndex(['sro_key_group']);
$table->text('sro_key_group')->change();
$table->renameColumn('sro_key_group', 'tags');
});
}
This is orginal migration create table file.
public function up()
{
Schema::create('service_request_type', function (Blueprint $table) {
$table->engine = 'InnoDB';
...
$table->string('sro_key_group', 100)->nullable()->index();
...
});
}
Error I got.
[Illuminate\Database\QueryException]
SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT
column 'sro_key_group' used in key specification without a key length
(SQL: ALTER TABLE service_request_type CHANGE sro_key_group sro _key_group TEXT DEFAULT NULL COLLATE utf8_unicode_ci)
[Doctrine\DBAL\Driver\PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT
column 'sro_key_group' used in key specification without a key length
[PDOException]
SQLSTATE[42000]: Syntax error or access violation: 1170 BLOB/TEXT
column 'sro_key_group' used in key specification without a key length
What wrong? And I already install doctrine/dbal in my composer.json.

You'll need to do this in three steps, either using three separate migrations, or three calls to table() as you've shown in your answer.
The first issue is that, even though you've written your statements in the order you'd like them to execute (and the order they need to execute), the schema builder will actually rearrange the order so that "change" statements are executed first. The schema builder treats new columns and changed columns as "implied" statements, and moves them to the top of the stack of commands to run. However, rename statements are not considered "change" statements.
So, even though you've written the code to:
[
remove index,
change column from varchar to text,
rename column,
]
The schema builder will actually execute:
[
change column from varchar to text,
remove index,
rename column,
]
Now, since the change command is happening before the column is removed from the index, you are getting the 1170 error.
The next issue is with attempting to do the column change and the column rename in the same context. The SQL to implement the requests changes is generated by doing schema diffs, however both schema diffs will be done before any changes are actually made. So, the first change from varchar to text will generate the appropriate SQL to make that change, but then the second change to rename the column will actually generate SQL that changes the column back to a text field while renaming it.
To work around these issues, you can either create three migrations, where the first migration simply drops the index, the second migration changes the type, and then the third migration renames it, or you can keep your one migration and run three table() statements.
public function up()
{
// make sure the index is dropped first
Schema::table('service_request_type', function (Blueprint $table) {
$table->dropIndex(['sro_key_group']);
});
// now change the type of the field
Schema::table('service_request_type', function (Blueprint $table) {
$table->text('sro_key_group')->nullable()->change();
});
// now rename the field
Schema::table('service_request_type', function (Blueprint $table) {
$table->renameColumn('sro_key_group', 'tags');
});
}

Ahhhhhh mannnnn...
I got the answer.
public function up()
{
Schema::table('service_request_type', function (Blueprint $table) {
$table->dropIndex(['sro_key_group']);
});
Schema::table('service_request_type', function (Blueprint $table) {
$table->text('sro_key_group')->nullable()->change();
});
Schema::table('service_request_type', function (Blueprint $table) {
$table->renameColumn('sro_key_group', 'tags');
});
}
Hmmmmmmm WTF is that?

Related

Cannot drop foreign key during Laravel's migration refresh

When I try to run php artisan migrate:refresh --seed on my tables, it always get stuck on this one:
public function down()
{
if (Schema::hasTable('leads')) {
Schema::table('leads', function (Blueprint $table) {
$table->dropForeign('leads_dealer_id_foreign'); //this is the line
$table->dropIndex('leads_dealer_id_index');
$table->dropColumn('dealer_id');
Schema::dropIfExists('leads');
});
}
}
The error is: Base table or view not found: 1146 Table 'leads' doesn't exist (SQL: alter table leads drop foreign key leads_dealer_id_foreign)
I've commented the line that produces the error in the snippet above.
Why would it complain about the table not existing? Even if the table doesn't exist, I've wrapped everything inside Schema::hasTable('leads') so it shouldn't even execute that line.
What causes my leads table to drop early? I've looked at my other migrations and nowhere I'm dropping that table except on its own migration file.
Thanks
You must drop the foreign keys first, then drop the table. In order to do this move Schema::dropIfExists('leads'); outside the closure:
public function down()
{
if (Schema::hasTable('leads')) {
Schema::table('leads', function (Blueprint $table) {
$table->dropForeign('leads_dealer_id_foreign'); //this is the line
$table->dropIndex('leads_dealer_id_index');
$table->dropColumn('dealer_id');
});
Schema::dropIfExists('leads');
}
}

Change foreign key unsignedBigInteger field to be text field in migration laravel

I have a table foo and a migration for it like this (just showing the up method):
public function up()
{
Schema::table('foo', function (Blueprint $table) {
$table->unsignedBigInteger('boo_id');
});
Schema::table('foo', function (Blueprint $table) {
$table->foreign('boo_id')->references('id')->on('boos');
});
}
So I have a boo_id foreign key on boos.id. Now I would like to create a migration that will alter the field boo_id to be text and not be foreign key anymore. How can I do that?
You first need to delete the foreign key and the index created for the foreign and then change the data type of the column. A migration like this would help:
public function up()
{
Schema::table('foo', function (Blueprint $table) {
$table->dropForeign('foo_boo_id_foreign');
$table->dropIndex('foo_boo_id_foreign');
});
Schema::table('foo', function (Blueprint $table) {
$table->text('boo_id')->change();
});
}
Please note that they must be in two seperate Schema::table bodies, otherwise you will face an error: Syntax error or access violation: 1170 BLOB/TEXT column 'boo_id' used in key specification without a key length (SQL: ALTER TABLE foo CHANGE boo_id boo_id TEXT DEFAULT NULL). Also note that the names passed to dropForeign and dropIndex functions might be different for you, you should check that in your DB to be sure, as that naming convention is not mandatory.

How to force case-sensitive column in Sqlite3 with Laravel 5.8

I tried to find solution but usually people writes about this in terms of string comparing, not the properties of column.
I have column with artists names, problem is column is case insensitive resulting in duplicate entry eg. "Depeche Mode" and "depeche mode" are two different records.
My Migration:
public function up()
{
Schema::create('artists', function (Blueprint $table) {
$table->increments('id');
$table->timestamps();
$table->string('name')->unique();
});
}
In code I'm trying to inserting artists in the loop using
$n_ar = \App\Artist::firstOrNew(['name'=>$artists[$i]]);
$n_ar->save();
I am using Sqlite3. Laravel documentation is unfortunately silent in terms of column modifiers like COLLATE and NOCASE in migrations.

Laravel Artisan - How to add and populate a new column into a table with existing records?

I wanted to add a new unique column called uuid into an existing table. This is my migration function.
public function up()
{
Schema::table('suppliers', function (Blueprint $table) {
$table->uuid('uuid')->index()->after('id');
});
}
However, the table already has existing records, ie 100+ records. How do I create a function to populate this new column with unique values for the existing records? Thanks.
you have to specify the type of the column so change $table->uuid to $table->string. so try following.
Schema::table('suppliers', function (Blueprint $table) {
$table->integer('uuid')->unique()->after('id');
});

laravel migration re-organising column order

When you create a new column in a table you can use the ->after('column name') to dictate where it goes. How can I create a migration that re-orders the columns in the right order I want?
Try this, hope it help you to find right solution:
public function up()
{
DB::statement("ALTER TABLE example MODIFY COLUMN foo DATE AFTER bar");
}
public function down()
{
DB::statement("ALTER TABLE example MODIFY COLUMN foo DATE AFTER bar");
}
If you want to do it without destroying data, you could migrate the data across at the same time you do the schema update:
use DB;
public function up()
{
//Give the moving column a temporary name:
Schema::table('users', function($table)
{
$table->renameColumn('name', 'name_old');
});
//Add a new column with the regular name:
Schema::table('users', function(Blueprint $table)
{
$table->string('name')->after('city');
});
//Copy the data across to the new column:
DB::table('users')->update([
'name' => DB::raw('name_old')
]);
//Remove the old column:
Schema::table('users', function(Blueprint $table)
{
$table->dropColumn('name_old');
});
}
I would suggest a DB::query('.. raw sql query ..'); and use the query from the answer "How to move columns in a MySQL table?"
Try this
public function up()
{
DB::statement("ALTER TABLE example CHANGE foo foo DATA_TYPE DATA_ATTRIBUTE(s) AFTER bar");
DB::statement("ALTER TABLE example CHANGE foo foo INT(10) UNSIGNED NOT NULL AFTER bar");
}
Alternatively if you too lazy to figure out the SQL, you can visit your phpMyAdmin, click your database, click your table, click the Structure tab, besides the column you want to move, click the change button, edit the last Move column column, click the Save button & then copy the SQL.
VERY IMPORTANT NOTE
Use the following solution only if you haven't launched your app yet (i.e. it's not yet used by any real users) as the following solution will delete the column and all data stored in it and will create a new empty column with the same name after the column you determine.
Suppose your column name is address and you want to reorder its position so that it comes after another column called city, and your table name is employees.
In your terminal type the next command:
php artisan migrate:make reorganize_order_of_column_address --table=employees
You may only change reorganize_order_of_column_address and employees according to your needs, but keep the rest of the command as it is.
This will generate a migration file in app/database/migrations folder, open it and put your code inside the up() function like this:
public function up()
{
Schema::table('employees', function(Blueprint $table)
{
$table->dropColumn("address");
});
Schema::table('employees', function(Blueprint $table)
{
$table->string('address')->after("city");
});
}

Resources