Cannot drop foreign key during Laravel's migration refresh - laravel

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');
}
}

Related

General error: 1824 Failed to open the referenced table

I am trying to set foreign key of my 'books' table with 'categories' table using php artisan migrate, but I got the following error:
Illuminate\Database\QueryException
SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'categories' (SQL: alter table `books` add constraint `books_category_id_foreign` foreign key (`category_id`) references `categories` (`id`))
books migration file:
public function up()
{
Schema::create('books', function (Blueprint $table) {
$table->increments('id');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories');
$table->string("image");
$table->string("title");
$table->string("description")->nullable();
$table->string("author");
$table->string("cover");
$table->integer("nod")->nullable();// Number of downloads
$table->integer("rating")->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('books');
}
categories migration file:
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string("title");
$table->string("image");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
I really need help with this to use in my mobile app API. I hope someone can help me.
The problem is on the migration itself. Have a look carefully at this
SQLSTATE[HY000]: General error: 1824 Failed to open the referenced table 'categories' (SQL: alter table `books` add constraint `books_category_id_foreign` foreign key (`category_id`) references `categories` (`id`))
You are trying to open the categories table but it basically wasn't there or wasn't created yet. If you use GUI like HeidiSQL or Navicat, or PMA, You will be able to see it.
Laravel migration takes the timestamp on the beginning of the file to decide which migration should be migrated first in sequence.
Make sure you create the categories table first before the books table (this also applies for any tables that has reference). Or simply just rename the file (change the timestamp) like E.g:
2020_01_01_1234_create_books_table.php
2020_01_01_5678_create_categories_table.php
to this
2020_01_01_1234_create_categories_table.php
2020_01_01_5678_create_books_table.php
Then run php artisan migrate:fresh to refresh your migration.
I faced the same issue with you since yesterday and I later saw my mistakes, I was able to understand the cause of the problem.
There are so many factors to consider
Make sure the date for the parent table (categories) is earlier than the date for the child table (books) so that during the migration, the parent table will be created first because the child table might want to reference id in a table that does not exist.
Make sure to follow the convention for naming
you can refactor your migration file like this
$table->foreignId('category_id')->constrained('categories');
or
$table->foreignId('category_id')->constrained();
example of one of my migration files
public function up()
{
Schema::create('project_details', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->charset = 'utf8mb4';
$table->collation = 'utf8mb4_unicode_ci';
$table->id();
$table->foreignId('project_id')->constrained()->onDelete('cascade');
$table->string('name', 150)->nullable();
$table->string('description', 600)->nullable();
$table->string('location', 150)->nullable();
$table->integer('completed_percent')->nullable()->default(0);
$table->foreignId('manager_id')->constrained('staffs');
$table->foreignId('sponsor_id')->constrained('sponsors')->nullable();
$table->foreignId('donor_id')->constrained('sponsors')->nullable();
$table->foreignId('mda_id')->constrained('sponsors')->nullable();
});
}
You try get category for book before you create category table and book table cant understand what you referenced for.
Solution #1
Declare your category table before book table, just rename date in migration file name. Category table must be created before book table.
Solution #2
Create reference after you create category table.
Remove
$table->foreign('category_id')->references('id')->on('categories');
from book migration and create references after you up category table.
categories migration file:
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->increments('id');
$table->string("title");
$table->string("image");
$table->timestamps();
});
Schema::table('books', function (Blueprint $table) {
$table->foreign('category_id')->references('id')->on('categories');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
Main idea is make all relations when all tables created.
Also, use php artisan migrate:fresh for fast wipe and recreate tables
I had the same error just right now.
It has something related to creating those migrations.
The problem I had because I refactored the table name manually and didn't take care of the connection between the tables and instantly tried to migrate them.
The solution I did and worked for me is I deleted the migrations manually and created them again using php make:magirate.
In my opinion you need to change the engine of the SQL to InnoDB, this issue was struggling with me for a lot of time all you need to do is adding
<?php
$table->engine = 'InnoDB';
?>
to the table migration file
reference :
https://web-brackets.com/discussion/4/-solved-sqlstate-hy000-general-error-1824-failed-to-open-the-referenced-table-alter-on-foreign-key-
The table (Categories) you are referencing its "id" is either not created or its created after the "books" table. You can manually delete both tables and create them again with "Categories" been first or you can manually change the date of the "Categories" to a date before the "books" and you are good to go.
Make sure you have such a table in your database. If you use a lot of database, then you need to specify the database for constrained
$connection_db = DB::connection('connection_name')->getDatabaseName();
$table->foreign('category_id')->references('id')->on("$connection_db.categories");
Make sure both the tables are created using the same engine. In my case, I created two tables with two different engines (MyISAM and InnoDB). Changing both the table engines to InnoDB did the trick.

Laravel:Can't drop foreign key even using 'dropForeign' method

I'm about to refresh my migration. But php artisan migrate:refresh command is not working.
It shows the following error:
[Illuminate\Database\QueryException] SQLSTATE[42000]: Syntax error
or access violation: 1091 Can't DROP 'classes_userid_foreign'; check
that column/key exists (SQL: alter table classes drop foreign key
classes_userid_foreign)
[PDOException] SQLSTATE[42000]: Syntax error or access violation:
1091 Can't DROP 'classes_userid_foreign'; check that column/key
exists
I even used the dropForeign but its not working for me.
I'm showing my migration file
public function up()
{
Schema::create('classes', function (Blueprint $table) {
$table->increments('id');
$table->integer('userId')->unsigned();
$table->string('title');
$table->string('name');
$table->string('code')->unique();
$table->integer('capacity')->unsigned();
$table->integer('tagId')->unsigned();
$table->foreign('userId')->references('id')->on('users');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('classes', function (Blueprint $table) {
$table->dropForeign(['userId']);
});
Schema::drop('classes');
}
How to fix this problem ?
Most times when you run migrations in laravel (whether up or down), and an error occurs along the line, the transaction may have completed partially without registering it in the migrations table.
If this is the case, or you will like to drop tables whether or not there really exists a foreign key, then you should consider disabling foreign key checks like so:
public function down()
{
Schema::disableForeignKeyConstraints();
Schema::drop('classes');
Schema::enableForeignKeyConstraints();
}

How to migration change columns type?

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?

Can't add foreign key in migration

I have one migration to execute. And here is my code:
public function up()
{
Schema::table('students', function (Blueprint $table) {
//
$table->foreign('phone_id')->reference('id')->on('phone');
});
}
where i execute migration, it said i have an error in my sql. And i run php artisan migrate --pretend to output the sql:
alter table `students` add constraint `students_phone_id_foreign` foreign key (`phone_id`) references `phone` ()
As you can see, there is a () at the end of the sql. How does it come out?
Schema::table('students', function ($table) {
$table->integer('phone_id')->unsigned();
$table->foreign('phone_id')->references('id')->on('phones');
});

Using migrations to delete table with foreign key

I am trying to roll back my migrations.
My migrations file uses foreign keys like so:
$table->foreign('user_one')->references('id')->on('users');
$table->foreign('user_two')->references('id')->on('users');
My down() function is like so:
public function down()
{
Schema::drop('pm_convo');
Schema::drop('pm_convo_replys');
}
When I run my migrate command:
php artisan migrate:refresh --seed --env=local
I am getting the following error:
SQLSTATE[23000]: Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails (SQL: drop table `pm_convo`)
I am not exactly sure what to do to fix this.
I have tried: $table->dropForeign('pm_convo_user_one_foreign');, but I am getting errors with that as well.
I think this is a better way to do it:
public function down()
{
DB::statement('SET FOREIGN_KEY_CHECKS = 0');
Schema::dropIfExists('tableName');
DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}
pm_convo_replys has a foreign key that references pm_convo, thus you cannot delete pm_convo first without violating a foreign key constraint in pm_convo_replys.
To delete both you need to delete pm_convo_replys first.
public function down()
{
Schema::drop('pm_convo_replys');
Schema::drop('pm_convo');
}
I also faced these kind of issues. Migration file order is the main issue here. The best way is to create migration files one by one. Main entities should be created first. Migration should be refreshed with every migrate file creation. (with php artisan migrate:refresh)
According to #abkrim and #Eric
public function down()
{
Schema::disableForeignKeyConstraints();
Schema::drop('tableName');
Schema::enableForeignKeyConstraints();
}
Or safer:
protected function dropColumn($table, $column) {
try {
Schema::disableForeignKeyConstraints();
Schema::table($table, function (Blueprint $tbl) use ($column) {
$tbl->dropColumn($column);
});
} catch (Illuminate\Database\QueryException $e)
{
Schema::table($table, function (Blueprint $tbl) use ($column) {
$tbl->dropConstrainedForeignId($column);
});
} finally {
Schema::enableForeignKeyConstraints();
}
}
public function down() {
$this->dropColumn('users', 'foreign_column');
}
I think this is the most correct approach:
public function down()
{
Schema::table('[table]', function (Blueprint $table) {
$table->dropForeign('[table]_[column]_foreign');
$table->dropColumn('[column]');
});
}
prefer to do it this way
Schema::dropIfExists('tableNameChild');
Schema::drop('tableNameParents');
Important, this is for Laravel 5.4.
According to the docs
To drop a foreign key, you may use the dropForeign method. Foreign key constraints use the same naming convention as indexes. So, we will concatenate the table name and the columns in the constraint then suffix the name with "_foreign"
$table->dropForeign('posts_user_id_foreign');
Or, you may pass an array value which will automatically use the conventional constraint name when dropping:
$table->dropForeign(['user_id']);
I personally prefer the second one because of simplicity
You can do that thing very easily if you added cascade on the foeign key when creating the table. If you did it, then you can remove the table very easily without something like this for PostgreSQL.
DB::statement("drop table if exists tableName cascade");
All you have to do is to put the statement for SQL table in the raw format.

Resources