#Laravel Migration: Cannot add foreign key constraint in laravel - laravel

I'm trying to create foreign keys in Laravel however when I migrate my table using artisan i am thrown the following error:
λ php artisan migrate
Migration table created successfully.
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `fees` add constraint `fee
s_fee_type_id_foreign` foreign key (`fee_type_id`) references `feetypes` (`fee_type_id`))
[PDOException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
My migration code is as so:
fees
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateFeesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('fees', function (Blueprint $table) {
$table->increments('fee_id');
$table->integer('academic_id')->unsigned();
$table->integer('level_id')->unsigned();
$table->integer('fee_type_id');
$table->string('fee_heading', 100)->nullable();
$table->float('amount', 8, 2);
$table->foreign('academic_id')->references('academic_id')->on('academics');
$table->foreign('level_id')->references('level_id')->on('levels');
$table->foreign('fee_type_id')->references('fee_type_id')->on('feetypes');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('fees');
}
}
fesstypes
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateFeetypesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('feetypes', function (Blueprint $table) {
$table->unsignedinteger('fee_type_id');
$table->string('fee_type', 100);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('feetypes');
}
}
Any ideas as to what I've done wrong, I want to get this right now, as I've got a lot of tables I need to create e.g. Users, Students, Leves, etc. Ideally I want to create tables which hold this data with the foreign keys, i..e fees and feetypes.
Hope someone can help me to get started.

Replace this line:
$table->integer('fee_type_id');
With this:
$table->unsignedInteger('fee_type_id');
In CreateFeesTable Migration.

Check all data types matches for the referenced data types.
public function up()
{
Schema::create('fees', function (Blueprint $table) {
$table->increments('fee_id');
$table->unsignedInteger('academic_id');
$table->unsignedInteger('level_id');
$table->unsignedInteger('fee_type_id');
$table->string('fee_heading', 100)->nullable();
$table->float('amount', 8, 2);
$table->foreign('academic_id')->references('academic_id')->on('academics');
$table->foreign('level_id')->references('level_id')->on('levels');
$table->foreign('fee_type_id')->references('fee_type_id')->on('feetypes');
});
}
check level_id in levels , academic_id in academics ,fee_type_id in feetypes are also unsignedInteger or autoincrement and change your table creating script to above one.

CreateFeesTable.php
change
$table->integer('fee_type_id');
to
$table->unsignedInteger('fee_type_id');
CreateFeetypesTable
change
$table->unsignedinteger('fee_type_id');
to
$table->increments('fee_type_id'); or
$table->integer('fee_type_id');

You must first create an index on the referenced column, i.e. fee_type_id in feetypes table.
MySQL requires indexes on foreign keys and referenced keys so that foreign key checks can be fast and not require a table scan. In the referencing table, there must be an index where the foreign key columns are listed as the first columns in the same order. Such an index is created on the referencing table automatically if it does not exist. This index might be silently dropped later, if you create another index that can be used to enforce the foreign key constraint. index_name, if given, is used as described previously.
From MySQL Reference Manual

Related

How to delete a record if it has a parent_id assigned?

I have a categories table that allows to have subcategories through the parent_id.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCategoriesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->unsignedBigInteger('parent_id')->unsigned()->nullable();
$table->string('slug');
$table->foreign('parent_id')->references('id')->on('categories');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('categories');
}
}
The problem comes when I want to delete a subcategory. I get an error when I have a foreign key.
SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails (`doogmas`.`categories`, CONSTRAINT `categories_parent_id_foreign` FOREIGN KEY (`parent_id`) REFERENCES `categories` (`id`)) (SQL: delete from `categories` where `id` = 30)
How can I delete the record even if I have the foreign key?
Try changing this
$table->foreign('parent_id')->references('id')->on('categories');
to
$table->foreign('parent_id')->references('id')->on('categories')->onDelete('cascade');
You can set how your database handles it when you delete a row:
$table->foreign('parent_id')->references('id')->on('categories')->onDelete('cascade');

SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint Laravel

Im trying to create a foreign keys using artisan, but this error show up.
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `comments` add constraint `comments_comment_lot_id_foreign` foreign key (`comment_lot_id`) references `lots` (`lot_id`
) on delete cascade)
This is my migration:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateCommentsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('comments', function (Blueprint $table) {
$table->increments('id');
$table->text('comment');
$table->integer('comment_lot_id')->unsigned();
$table->timestamps();
});
Schema::table('comments', function ($table) {
$table->foreign('comment_lot_id')->references('lot_id')->on('lots')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropForeign(['comment_lot_id']);
Schema::dropIfExists('comments');
}
}
in the lots table i use lot_id as id it model Lot.php i add:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Lot extends Model {
protected $primaryKey = 'lot_id';
}
Any idea how can i resolve this error?
Apply these rules below to your migration files:
[1]
The parent, pivot table(s) must be based on engines that supports
foreign key referencing (e.g InnoDB for mysql).
Do $table->engine = “InnoDB”;
in your migration file, right before other column definitions.
I observe laravel always default to MyISAM hence this line is a must.
[2]
The referenced columns in the parent must be a primary or unique
key(s).
These declarations in the parent table are fine:
$table->increments(“id”); means column “id” is referencable
$table->column_type(“column_name”)->unique(); means column “column_name” is referencable
[3]
The pivot table column must be of the same type as that of its
referenced parent table column.
So for example, the pivot table column that should reference increments(“id”) must of type of unsignedInteger.
If parent table is type char(20), then pivot table column used to reference it must be type char(20) as well.
Having done all three above, define your foreign key relationship as appropriate.
Looks like this was not the problem for you, but I arrived at this same error in Laravel 5.8 and found an interesting issue: Laravel now defaults the 'id' column to 'bigIncrements' instead of just 'increments'. So instead of referencing it with 'integer' like before, you have to reference it with 'bigInteger'.
If your parent table looks like this:
$table->bigIncrements('id');
Then the child migration needs to look like this:
$table->bigInteger('parent_id')->unsigned()->index();
$table->foreign('parent_id')->references('id')->on('parent');
Hopefully this helps anyone else encountering this problem in 5.8 and beyond.
Quoting this answer:
To find the specific error run this:
SHOW ENGINE INNODB STATUS;
And look in the LATEST FOREIGN KEY ERROR section.
It may be a problem of type. comment_lot_id must be the exact same type as lot_id. Maybe one is signed and the other unsigned.

Can't create foreign key with laravel database migration

I have a problem with my Laravel migrations :(
when i'm running php artisan migrate, it stops on a foreign key.
first migration
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::enableForeignKeyConstraints();
Schema::create('fichefrais', function (Blueprint $table) {
$table->char('idVisiteur', 4);
$table->foreign('idVisiteur')->references('id')->on('visiteur');
$table->char('mois',6);
$table->primary(['idVisiteur', 'mois']);
$table->integer('nbJustificatifs');
$table->decimal('montantValide', 10, 2);
$table->date('dateModif');
$table->char('idEtat', 2);
$table->foreign('idEtat')->references('id')->on('etat');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('fichefrais');
}
and the second
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::enableForeignKeyConstraints();
Schema::create('lignefraishorsforfait', function (Blueprint $table) {
$table->integer('id');
$table->primary('id');
$table->char('idVisiteur', 4);
$table->char('mois',6);
$table->foreign('idVisiteur')->references('idVisiteur')->on('fichefrais');
$table->foreign('mois')->references('mois')->on('fichefrais');
$table->char('libelle', 100);
$table->date('date');
$table->decimal('montant', 10, 2);
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('lignefraishorsforfait');
}
After running the command, I got this error :
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1005 Can't create table
gsb_larave.#sql-176_b9 (errno: 150 "Foreign key constraint is
incorrectly formed") (SQL: alter table lignefraishors forfait
add constraint lignefraishorsforfait_mois_foreign foreign key
(mois) references fichefrais (mois) on delete cascade on update
cascade)
[PDOException]
SQLSTATE[HY000]: General error: 1005 Can't create table
gsb_laravel.#sql-176_b9 (errno: 150 "Foreign key constraint is
incorrectly formed")
Does your visiteur table has an id as a primary key? If yes, does it have a data type has char and a length of 4. The idVisiteur in ** lignefraishorsforfait** table has a data type of char which must be the same as the primary key in the visiteur table.
The problem is that the foreign key you are declaring doesn't refer to a primary key. If you want to create a foreign key to a non-primary key, the column 'mois' in your 'fichefrais' table must be a column with a unique constraint on it
First of all your foreign keys must refer to a primary key (which most of the time is 'id' column).
Also you should create the tables in this order:
1- 'etat' table(which i dont see bcs you did not posted the migration code,),
2- 'fichefrais' table,
3- 'lignefraishorsforfait' table.
Just change the dates on database/migrations like this (example):
2020_09_11_150331_create_etat_table.php
2020_09_12_000000_create_fichefrais_table.php
2020_09_13_000000_create_lignefraishorsforfait_table.php
You cannot create first the table which contains foreign key because will not have a key in which to refer.
Use this migrations:
First migration (fichefrais):
public function up()
{
Schema::create('fichefrais', function (Blueprint $table) {
$table->integer('idVisiteur')->unsigned()->nullable();
$table->foreign('idVisiteur')->references('id')->on('visiteur');
$table->char('mois',6);
$table->primary(['idVisiteur', 'mois']);
$table->integer('nbJustificatifs');
$table->decimal('montantValide', 10, 2);
$table->date('dateModif');
$table->integer('idEtat')->unsigned()->nullable();
$table->foreign('idEtat')->references('id')->on('etat');
});
}
Second migration (lignefraishorsforfait):
public function up()
{
Schema::create('lignefraishorsforfait', function (Blueprint $table) {
$table->integer('id');
$table->primary('id');
$table->integer('mois')->unsigned()->nullable();
$table->foreign('mois')->references('mois')->on('fichefrais');
$table->integer('idVisiteur')->unsigned()->nullable();
$table->foreign('idVisiteur')->references('idVisiteur')->on('fichefrais');
$table->char('libelle', 100);
$table->date('date');
$table->decimal('montant', 10, 2);
});
}
You are using MySQL, so Are your tables defined in InnoDB engine? MyISAM doesn't accept foreign key...

I cannot add or update a child row a foreign key constraint fails

I'm using laravel 5, I'm having an issue while adding a column to a table
[Illuminate\Database\QueryException]
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (homest
ead.#sql-4f4_a9, CONSTRAINT posts_user_id_foreign FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE) (SQ
L: alter table posts add constraint posts_user_id_foreign foreign key (user_id) references users (id) on delete cascade
)
The code below should work for you. I tested it in my own setup.
Make sure the posts table is deleted from your database before running this migration. Otherwise it may fail.
If it's not deleted by reversing the migration you could delete it manualy. If you do so don't forget to delete the rule from the migrations table in your database.
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class ToPostTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('posts', function(Blueprint $table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->text('body');
$table->timestamps();
$table->timestamp('published_at');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('posts');
}
}
Make sure you have user_id in the fillable property of your Post model.
http://laravel.com/docs/5.0/eloquent#mass-assignment

Laravel Unit Testing Migration fails

I am trying to run PHPUnit test. I have setup SQLite in :memory for the testing environment. In my setup, I call Artisan::call('migrate') but then I get the following error:
General error: 1 Cannot add a NOT NULL column with default value NULL
(SQL: alter table "admins" add column "title" text not null)
Basically, any migration file that is modifying an existing table returns an error. Why?
Here is the file migration is complaining about:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
class AddTitleToAdminsTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::table('admins', function(Blueprint $table)
{
$table->text('title');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('admins', function(Blueprint $table)
{
$table->dropColumn('title');
});
}
}
I did some research and found this post on Stack Overflow.
It appears that SQLite has a problem with columns that are NOT NULL but have no default value. When in the same situation, MySQL just uses an empty string (for varchar) or "0" (for numbers). So it kind of has built in default values.
To solve your problem you can either make the column nullable (only if you want it to be nullable) or define a default.
$table->text('title')->nullable();
$table->text('title')->default('');

Resources