I am having some issues with deleting data using Laravel 5. I seem to be stuck on a 'foreign key constraint', while I don't see why.
In my current database model I have a datapoints table, which has a foreign key to the sensors table (datapoints.sensors_id -> sensor.id).
The code I am trying:
Route::get('/truncateData', function() {
DB::table('datapoints')->truncate();
DB::table('sensors')->truncate();
return 'Done...';
});
The result:
SQLSTATE[42000]: Syntax error or access violation: 1701 Cannot
truncate a table referenced in a foreign key constraint
(alerting.datapoints, CONSTRAINT datapoints_sensor_id_foreign
FOREIGN KEY (sensor_id) REFERENCES alerting.sensors (id))
(SQL: truncate sensors)
I would understand this constraint if the order would be inverse (first deleting sensors), but when datapoints is empty, there should be no problem deleting sensors? I have also tried:
DB::table('datapoints')->delete();
DB::table('sensors')->delete();
return 'Done...';
Lastly I also tried adding explicitly 'DB::commit()' between the delete statements, but all return the same result.
Is this normal behaviour? Am I missing something?
No, this is the way your database works. You can't truncate table that is referenced by some other table. You may do something like
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
DB::table('datapoints')->truncate();
DB::table('sensors')->truncate();
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
to disable foreign key checks, truncate tables and enable it again.
If you prefer to use Eloquent objects, Maksym's answer the "Eloquent" way
use Illuminate\Support\Facades\Schema;
use App\Models\Datapoint;
use App\Models\Sensor;
Schema::disableForeignKeyConstraints();
Datapoint::truncate();
Sensor::truncate();
Schema::enableForeignKeyConstraints();
In Laravel 7 and 8, for compatibility across 4 databases (MySql, Postgres, SQLite and SqlServer) and no Eloquent, you can use:
Schema::disableForeignKeyConstraints();
DB::table('datapoints')->truncate();
DB::table('sensors')->truncate();
Schema::enableForeignKeyConstraints();
Related
So I've been trying to write a migration that creates a data table question_display_formats using tiny increments as you see below.
And then, adding new Foreign Key column to existing questions table, trying to use the foreignIdFor method as a shortcut that'd look nice
public function up()
{
Schema::create('question_display_formats', function (Blueprint $table) {
$table->tinyIncrements('id');
$table->string('format');
});
Schema::table('questions', function (Blueprint $table) {
$table->foreignIdFor(QuestionDisplayFormat::class)
->nullable(true)
->after('question_type_id')
->constrained();
});
}
Turns out, this errors out with
General error: 1215 Cannot add foreign key constraint
Which turns out because the foreignIdFor users a different data type (confirmed by manually matching them and running the erroring out SQL alter table statement).
I googled, read and tried to adjust by doing:
$table->mediumIncrements('question_display_format_id'); before the foreignIdFor line, which leads to error
SQLSTATE[42S21]: Column already exists: 1060 Duplicate column name
'question_display_format_id' (SQL: alter table questions add
question_display_format_id mediumint un signed not null
auto_increment primary key, add question_display_format_id bigint
unsigned null after question_type_id)
Is there a way to use foreignIdFor with the matching column size? or am I supposed to fall back on the classic way of first creating the column explicitly, then doing like $table->foreign('question_display_format_id')->references('id')->on('question_display_formats'); which I don't like because its very verbose and doesn't look good?
On the other hand, this is a one time used script.. lol would've been faster to just do it the old way! but I am curious to see how to do it right :)
To prevent "SQLSTATE[42000]: Syntax error or access violation: 1701 Cannot truncate a table referenced in a foreign key constraint.." when running DatabaseSeeder(.php) method run(), I set foreign key checks to 0, then call table seeders, and after that set foreign key checks again to 1. I feel like this isn't the best thing to do here, so I'd like to know what's the best syntax solution (if this isn't):
public function run()
{
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
$this->call(RolesTableSeeder::class);
$this->call(UsersTableSeeder::class);
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
}
The best solution is to delete the objects referenced in foreign key constraints first.
I'm working with Laravel in this new project but there's one piece of code that I don't know what it does.
$table->foreign('course_id', '54419_596eedbb6686e')->references('id')->on('courses');
The line above is one of my migration files, I know that I'm saying that the 'course_id' is a foreign key with relation to 'id' on courses table. But what I don't know is what is this second parameter ('54419_596eedbb6686e'), if I look in the method description it says that is a name, but a name for what? Am I supposed to create a number like this and put it in all my foreign keys? Is there a command to generate this number?
Anyway if anyone can help me to understand this piece of code it would be great.
Hope I was clear on the question.
The second parameter is the name for your foreign key.
By default the name of the foreign key for this $table->foreign('course_id')->references('id')->on('courses'); will be courses_course_id_foreign.
In this case $table->foreign('course_id', '54419_596eedbb6686e')->references('id')->on('courses'); your foreign key will be named as 54419_596eedbb6686e.
When you create a foreign key you are creating a constraint and that's what the second parameter of foreign() function is specifying: the constraint name.
If you are using mysql you can log in the shell(or whatever program you use to check the db out) and run SHOW CREATE TABLE table_name. that will output information about that table you specified. There you'll be able to see '54419_596eedbb6686e' as a constraint of your table. Something like this:
CONSTRAINT constraint_name FOREIGN KEY (column_id) REFERENCES table_name (id) ON DELETE CASCADE
You can find a little more information in the following links: MySQL FOREIGN KEY syntax
SQL FOREIGN KEY on CREATE TABLE
When you create migration let this in your migration for foreign key
$table->foreign('foreign_id')
->references('id')->on('main_table_name')
->onUpdate('CASCADE')
->onDelete('RESTRICT');
I am making my table like this...
Schema::create('matched_merchants', function (Blueprint $table)
{
$table->increments('id')->unsigned();
$table->integer('merchant_id')->unsigned();
$table->integer('offer_id')->unsigned();
$table->foreign('merchant_id')->references('id')->on('merchants')->onUpdate('cascade')->onDelete('restrict');
$table->foreign('offer_id')->references('id')->on('offers')->onUpdate('cascade')->onDelete('restrict');
});
Im adding 2 foreign keys both have onUpdate and onDelete constraints but only the update constraint gets added.
If i delete the onUpdate, it will correctly add the onDelete constraint.
I cannot add them separately because i get the error of duplicate key.
I could add them manually with a raw sql statement but if theres a right way to do it id rather do that.
For some reason, if you set the columns as nullable(), Laravel sets the foreign keys correctly.
That said, I can see that causing other problems, so I recommend doing the raw SQL statement.
I've tried to drop a an InnoDB table that holds a foreign key using Laravel Migrations but I found out that I need to drop the foreign first but what I've read on the doc and on articles doesn't work.
Here's the portion of the code creating the problem :
Schema::table('admin_admin_action', function(Blueprint $table) {
$table->dropForeign(['admin_action_id']);
$table->dropColumn('admin_action_id');
$table->dropForeign(['admin_id']);
$table->dropColumn('admin_id');
});
And here's the error code
Illuminate\Database\QueryException : SQLSTATE[42000]: Syntax error or access violation: 1091 Can't DROP 'admin_admin_action_admin_action_id_foreign'; check that column/key exists (SQL: alter table `admin_admin_action` drop foreign key `admin_admin_action_admin_action_id_foreign`)
This table is the result of a many to many association and here are the foreign keys
Schema::table('admin_admin_action', function($table) {
$table->unsignedInteger('admin_id');
$table->unsignedInteger('admin_action_id');
$table->foreign('admin_id')->references('id')->on('admin');
$table->foreign('admin_action_id')->references('id')->on('admin_actions');
});
I've also tried specifying the full foreign key name but it says that the key/column doesn't exist though it does exist in the database.
I'm doubting this is a migration's issue because the migration runs smoothly but that's not the case for the rollback.
Edit: The foreign keys are respectively named
admin_admin_action_admin_id_foreign
admin_admin_action_admin_action_id_foreign
Help!
I found the solution !
You're right ! It's a mis-conception issue I've created a "admin_admin_action" and an "admin_action_admin" tables. So I've been trying to the table that doesn't have the foreign keys but has the same position in the database. They're duplicated ! Thanks