Reputation: 9693
My present table is
Schema::create('students', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('first_name', 255);
$table->string('last_name', 255);
$table->enum('gender', ['m', 'f']);
$table->date('date_of_birth');
$table->integer('roll_number');
$table->char('section', 1);
$table->integer('class');
$table->unsignedBigInteger('school_id');
$table->string('photo')->nullable;
$table->timestamps();
$table->foreign('school_id')
->references('id')->on('schools')
->onUpdate('cascade')->onDelete('cascade');
$table->unique(['roll_number', 'section', 'class', 'school_id']);
});
Standards
Schema::create('standards', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->unsignedBigInteger('school_id');
$table->timestamps();
$table->foreign('school_id')
->references('id')->on('schools')
->onUpdate('cascade')->onDelete('cascade');
});
Sections
Schema::create('sections', function (Blueprint $table) {
$table->bigIncrements('id');
$table->char('name', 1);
$table->unsignedBigInteger('standard_id');
$table->timestamps();
$table->foreign('standard_id')
->references('id')->on('standards')
->onUpdate('cascade')->onDelete('cascade');
});
now I have standards and sections table and foreign keys from these tables will replace the class and section columns in existing structure and maintain the combination of roll_number
, section_id
, standard_id
and school_id
as unique.
I tried
public function up()
{
Schema::table('students', function (Blueprint $table) {
$table->dropUnique(['roll_number', 'section', 'class', 'school_id']);
$table->dropColumn('section');
$table->dropColumn('class');
$table->unsignedBigInteger('standard_id')->after('roll_number');
$table->unsignedBigInteger('section_id')->after('standard_id');
$table->foreign('standard_id')->references('id')->on('standards')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('section_id')->references('id')->on('sections')
->onUpdate('cascade')->onDelete('cascade');
$table->unique(['roll_number', 'standard_id', 'section_id', 'school_id']); // unique combination
});
}
but it seems to be not working.
Error
Illuminate\Database\QueryException : SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (
myapp_extra
.#sql-2f78_29d
, CONSTRAINTstudents_standard_id_foreign
FOREIGN KEY (standard_id
) REFERE NCESstandards
(id
) ON DELETE CASCADE ON UPDATE CASCADE) (SQL: alter tablestudents
add constraintstudents_standard_id_foreign
foreign key (standard_id
) referencesstandards
(id
) on delete cascade on update cascade)at \myapp\vendor\laravel\framework\src\Illuminate\Database\Connection.php:664
Note: standards and sections table are created, before making this migration, so both columns are available.
Upvotes: 1
Views: 245
Reputation: 10254
This error is occurring because you are inserting a new column without default value and without NULLABLE
to your table that already has rows.
When you do it, MySQL will set it value to 0
, so all your tables will have standard_id
and section_id
set to 0
, so when you try to add your foreign index, it fails because 0
is not a valid id on your standards
/sections
table.
You have some ways to solve this issue:
If make sense for your application, you can set a default (valid) value to your column, so the foreign key won't fail:
$table->unsignedBigInteger('standard_id')->default(1)->after('roll_number');
$table->unsignedBigInteger('section_id')->default(1)->after('standard_id');
Most times it's not so simple, so you will need to define the value dinamically
If you have some logic to set the default value for this new columns, you can break you migration into two steps:
// Add the fields first
Schema::table('students', function (Blueprint $table) {
$table->dropUnique(['roll_number', 'section', 'class', 'school_id']);
$table->dropColumn('section');
$table->dropColumn('class');
$table->unsignedBigInteger('standard_id')->after('roll_number');
$table->unsignedBigInteger('section_id')->after('standard_id');
}
App\Students::get()->each(function($student) {
// Apply your logic here
$student->standard_id = 3;
$student->section_id = 3;
$student->save();
});
// Now you can add your foreign keys.
Schema::table('students', function (Blueprint $table) {
$table->foreign('standard_id')->references('id')->on('standards')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('section_id')->references('id')->on('sections')
->onUpdate('cascade')->onDelete('cascade');
$table->unique(['roll_number', 'standard_id', 'section_id', 'school_id']); // unique combination
});
If you just don't know or don't have a default value for this fields, so your field should be nullable instead:
$table->unsignedBigInteger('standard_id')->nullable()->after('roll_number');
$table->unsignedBigInteger('section_id')->nullable()->after('standard_id');
Upvotes: 1