I have a calls table with user_id column and a foreign key constrain. So, user_id is related to users table.
I made a migration which deletes the column and foreign key constrain. The up method works fine. However, when it comes to down it breaks down because I add a user_id column and then restore the constrain, but the values in the column have nothing to do with real data so I got 150 MySQL error.
I've found a solution which didn't work for me. The solution is to temporarily disable foreign key constrains. Here is my migration file:
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class RemoveUseridFromCalls extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::table('calls', function(Blueprint $table)
{
$table->dropForeign('calls_user_id_foreign');
$table->dropColumn('user_id');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
\DB::statement('SET FOREIGN_KEY_CHECKS = 0');
Schema::table('calls', function(Blueprint $table)
{
$table->integer('user_id')->unsigned();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('set null');
});
\DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}
}
But I still get the same error.
So, the questions are:
What would you do if you need to remove user_id from columns table as it's not needed anymore, however you have to write the down method as well as up?
Why disabling foreign key checks doesn't work?
I use InnoDB as table type for all my tables.
You can simply use onDelete('cascade').
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('calls', function(Blueprint $table)
{
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade'); // use 'cascade'
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('calls');
}
}
onDelete('cascade') tells Laravel to delete a calls row when it's corresponsding foreign key user_id is deleted.
I had the same problem and fixed it by separating migration into several files. First one creates the table, the others add columns for the keys and the keys themselves.
After that everything starts working like a charm.
To check foreign key in table while dealing with migration can be as follow:
$keyExists = DB::select(DB::raw('SHOW KEYS FROM TABLE_NAME WHERE Key_name=\'YOUR_FOREIGN_KEY_NAME\''));
if(!$keyExists){
$table->foreign('app_id')
->references('id')
->on('apps')
->onDelete('cascade');
}
Related
I am using Laravel 8.21.0 on a CentOS 8 server. I am using mariaDB. I have 3 tables: tests, students and grades.
I am trying to set foreign key of tests and students on the grades table.
However, when I run my migrations, I get errorno 150: Foreign key constraint is incorrectly formed.
Here are my migrations:
Grades table:
class CreateGradesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('grades', function (Blueprint $table) {
$table->id('id')->unique();
$table->unsignedInteger('student_id');
$table->string('test_id');
$table->foreign('test_id')->references('id')->on('tests');
$table->foreign('student_id')->references('id')->on('students');
$table->date('testDate');
$table->integer('testCount');
$table->integer('vocabScore');
$table->integer('readingScore');
$table->integer('listeningScore');
$table->integer('rawTotal');
$table->integer('adjustVocabScore');
$table->integer('adjustReadingScore');
$table->integer('adjustlisteningScore');
$table->integer('adjustTotal');
$table->string('passOrfail');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('grades');
}
}
Student Table migrations:
class CreateStudentsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('students', function (Blueprint $table) {
$table->integer('id')->unique();
$table->string('name');
$table->date('DOE');
$table->string('belongsTo');
$table->string('country');
$table->string('level');
$table->string('year');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('students');
}
}
Test table:
class CreateTestsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('tests', function (Blueprint $table) {
$table->string('id')->unique();
$table->string('testName');
$table->string('level');
$table->integer('vocabFullScore');
$table->integer('readingFullScore');
$table->integer('listeningFullScore');
$table->integer('totalFullScore');
$table->integer('vocabPassScore');
$table->integer('readingPassScore');
$table->integer('listeningPassScore');
$table->integer('totalPassScore');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('tests');
}
}
The bizzare thing is that the migrations table gets created successfully when I run it on localhost WAMP server but it throws me an error on CENTOS server. Does anyone have any idea on how to solve this?
Things that I have tried doing but did not work:
・Changed database to InnoDB by specifying 'engine' => 'InnoDB' on each model.
・Made sure that the order of migration is correct. First migrated student table, then tests and lastly grades.
・Ensure that the data type of the foreign key is correct on grades table.
Any ideas would be greatly appreciated. :'(
Edit: I set the foreign key type of student_id as integer.
In grades table migration:
$table->integer('student_id');
$table->foreign('student_id')->references('id')->on('students');
In students table migration:
$table->integer('id')->unique();
After doing this I am getting a new error:
Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for right syntax to use near ')' at line 1 (SQL: alter table 'grades' add constraint 'grades_test_id_foreign' foreign key ('test_id') references 'tests' ())
at vendor/laravel/framework/src/Illuminate/Database/Connection.php:678
catch(Exception $e){
throw new QueryException(
$query, $this->prepareBindings($bindings),$e
);
}
+9 vendor frames
database/migrations/2021_01_13_064711_create_grades_table.php:54
Illuminate\Support\Facades\Facade::__callStatic()
+32 vendor frames
artisan:37
Illuminate\Foundation\Console\Kernel::handle()
Change
$table->unsignedInteger('student_id');
to
$table->integer('student_id');
in grades table to match the datatypes to form a constraint.
I need to connect two tables in DB with relation one to one. Where 'id' from first table need to be the 'id' in the second table.
Table 1:
public function up()
{
Schema::disableForeignKeyConstraints();
Schema::create('devices', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('device_type', 20)->nullable();
$table->date('purchase_date')->nullable();
$table->date('activation_date')->nullable();
$table->date('deactivation_date')->nullable();
$table->bigInteger('companyId')->unsigned();
$table->timestamps();
$table->foreign('companyId')->references('id')->on('companies');
});
Schema::enableForeignKeyConstraints();
}
Table 2:
public function up()
{
Schema::disableForeignKeyConstraints();
Schema::create('device_news', function (Blueprint $table) {
$table->integer('x', 10)->nullable();
$table->integer('y', 10)->nullable();
$table->time('time')->nullable();
$table->bigIncrements('deviceId');
$table->timestamps();
$table->foreign('deviceId')->references('id')->on('devices');
});
Schema::enableForeignKeyConstraints();
}
I never had situation like this. Is it correct or I have to change something?
To create an Eloquent model for a legacy table that has no primary key, simply add the following to your model:
/**
* primaryKey
*
* #var integer
* #access protected
*/
protected $primaryKey = null;
/**
* Indicates if the IDs are auto-incrementing.
*
* #var bool
*/
public $incrementing = false;
You should still have a $table->bigIncrements('id'); on the second table, so the table gets a PK - but you create the relation on an unsigned biginteger, which is not a primary key.
Laravel naming conventions also dictates that a relational column should be device_id and not deviceId (same goes for your primary table, it should be company_id and not companyId). Doing this will make your life much easier when you start defining your relations on your models.
Schema::create('device_news', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedBigInteger('device_id');
$table->integer('x', 10)->nullable();
$table->integer('y', 10)->nullable();
$table->time('time')->nullable();
$table->timestamps();
$table->foreign('device_id')->references('id')->on('devices');
});
I have table with primary key and auto-increment field, I want make new migration to drop primary key index and also remove the auto increment field. How can i achieve this.
I created new migration as
public function up()
{
Schema::table('tbl_message_read_state', function (Blueprint $table) {
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('tbl_message_read_state', function (Blueprint $table) {
$table->dropPrimary('message_id');
$table->unsignedInteger('message_id');
});
}
It gave me error in command as [Illuminate\Database\QueryException]
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name 'message _id' (SQL: alter table tbl_'message_read_state' add 'message_id' int unsigned not null)
Whats Wrong ?????
Blueprint class offers dropPrimary methods that allow you to remove primary key.
public function down()
{
Schema::table('table', function (Blueprint $table) {
$table->dropPrimary();
$table->unsignedInteger('id'); // for removing auto increment
});
}
This did it for me:
Schema::table('table_name', function (Blueprint $table) {
// Make AI field `id` unsigned otherwise SQL
// will throw error when you try to remove it
$table->integer('id')->unsigned()->change();
$table->dropColumn('id');
// If there was a foreign on message_id, make sure to remove it
$table->dropForeign('table_name_message_id_foreign');
$table->dropPrimary('message_id');
$table->dropColumn('message_id');
}
The dropPrimary method only removed the primary key, not the column. You would have to do:
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('tbl_message_read_state', function (Blueprint $table) {
$table->dropPrimary('message_id');
$table->dropColumn('message_id');
$table->unsignedInteger('message_id');
});
}
Or instead of dropping and re-creating the column, you can use change in Laravel 5.
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('tbl_message_read_state', function (Blueprint $table) {
$table->dropPrimary('message_id');
$table->integer('message_id')->unsigned()->change();
});
}
You can try this
$table->dropPrimary('id_primary');
Drop the primary key:
$table->dropPrimary( 'id' );
Reference
Use a simple drop column
$table->dropColumn('id');
https://laravel.com/docs/4.2/schema#dropping-indexes
tabel_name
column
index $table->dropPrimary('users_id_primary');
in my database i have already tables namely: notifications table, statuses table, they have many to many relation, that is why i have a pivot table called notification_status. i created them with migrations and seed them with a seeder, all works fine. now i realize that i need one extra table which has many to one relation with notifications table(natification->hasMany->alertfrequency). when i tried to migrate it, it did allow me to do so.
here is my notification table
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateNotificationsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('notifications', function (Blueprint $table) {
$table->increments('id');
$table->string('website_url');
$table->string('email');
$table->string('slack_channel');
$table->string('check_frequency');
$table->string('alert_frequency');
$table->string('speed_frequency');
$table->boolean('active');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('notifications');
}
}
and the alert frequency table, the new table i want to add,
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateAlertFrequenciesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('alertFrequencies', function (Blueprint $table) {
$table->increments('id');
$table->integer('notification_id');
$table->foreign('notification_id')
->references('id')->on('notifications')
->onDelete('cascade');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('alertFrequencies');
}
}
when i tried to add i get the following constrain
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL: alter table `alertFrequencies` add constraint `alertfrequencies_notification_id_foreign` foreign key (`notification_
id`) references `notifications` (`id`) on delete cascade)
any one with a idea or suggestion. i appreciate all idea and suggestions.
From #AlexeyMezenin's answer, update based on Documentation:
Replace
$table->integer('notification_id')->unsigned();
with
$table->unsignedInteger('notification_id');
First thing you should do is to add unsigned(), because id is unsigned too:
$table->integer('notification_id')->unsigned();
If it'll not help, divide key creation and adding a foreign key constraint:
Schema::create('alertFrequencies', function (Blueprint $table) {
$table->increments('id');
$table->integer('notification_id')->unsigned();
$table->timestamps();
});
Schema::table('alertFrequencies', function (Blueprint $table) {
$table->foreign('notification_id')->references('id')->on('notifications')->onDelete('cascade');
});
You need to migrate notifications table prior to alertFrequencies table as notification_id of alertFrequencies is referencing id of notifications table.
And you need to change $table->integer('notification_id'); to $table->integer('notification_id')->unsigned(); as you cannot accept minus ids as foreign key
And also make sure you have set your table engine set to InnoDB in your `config/database.php'.
$table->engine = 'InnoDB';
I have the following migration file declared in laravel:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateProductsTable extends Migration {
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('products' , function($table){
$table->increments('id');
$table->integer('category_id');
$table->string('title');
$table->text('description');
$table->decimal('height' , 6 , 2);
$table->decimal('width' , 6 , 2);
$table->decimal('length' , 6 , 2);
$table->string('color');
$table->string('material');
$table->timestamps();
});
Schema::table('products' , function($table){
$table->foreign('category_id')->references('id')->on('categories');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::drop('products');
}
}
now when i run php artisan migrate
i get an error , because the id in categories is int(10) and the categories_id I.E.
$table->foreign('category_id')->references('id')->on('categories');
is int(11) how do i make both int(10) ?
I would guess that your previous migrations were run on a previous version of Laravel. If that's the case, you can simply modify the column type of categories.id to int(11) directly in the DB.
Otherwise, you could use a Raw Query to add the column using INT(10).
To confirm the hypothesis that a version change caused this, you could run ALL migrations in an empty DB and see if you have the same issue.
Schema::table('products', function($table)
{
$table->integer('id, 10');
});