Laravel 迁移:"Foreign key constraint is incorrectly formed"(错误号 150)
Laravel migration: "Foreign key constraint is incorrectly formed" (errno 150)
迁移我的数据库时,出现此错误。下面是我的代码,后面是我在尝试 运行 迁移时遇到的错误。
代码
public function up()
{
Schema::create('meals', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('category_id')->unsigned();
$table->string('title');
$table->string('body');
$table->string('meal_av');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade');
});
}
错误信息
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1005 Can't create table
meal
.#sql-11d2_1 4
(errno: 150 "Foreign key constraint is
incorrectly formed") (SQL: alter
table meals
add constraint meals_category_id_foreign foreign key (category_id
) references categories
(id
) on delete
cascade)
@JuanBonnett 的 启发了我寻找答案。我使用 Laravel 来自动执行该过程,而不考虑文件本身的创建时间。根据工作流程,“膳食”将在其他 table(类别)之前创建,因为我在类别之前创建了它的架构文件(膳食)。
那是我的错。
在我的例子中,问题是引用的表之一是 InnoDB,另一个是 MyISAM.
MyISAM 不支持外键关系。
所以,现在 两个 表都是 InnoDB。问题已解决。
必须自上而下创建迁移。
首先为 table 不属于任何人的人创建迁移。
然后为属于前一个的 table 创建迁移。
table 引擎问题的简化答案:
要为 table 设置存储引擎,请在架构构建器上设置引擎 属性:
Schema::create('users', function ($table) {
$table->engine = 'InnoDB';
$table->increments('id');
});
来自 Laravel 文档:https://laravel.com/docs/5.2/migrations
也许它对登陆这里的任何人都有帮助:我刚刚遇到了同样的问题,在我的情况下,我在外键约束之前的外键列上设置了一个(复合)唯一约束。我通过将 "unique" 语句放在 "foreign" 语句之后解决了这个问题。
作品:
$table->foreign('step_id')->references('id')->on('steps')->onDelete('cascade');
$table->unique(['step_id','lang']);
无效:
$table->unique(['step_id','lang']);
$table->foreign('step_id')->references('id')->on('steps')->onDelete('cascade');
对我来说,一切都按正确的顺序进行,但仍然无法正常工作。后来摸索发现主键必须是无符号的
//this didn't work
$table->integer('id')->unique();
$table->primary('id');
//this worked
$table->integer('id')->unsigned()->unique();
$table->primary('id');
//this worked
$table->increments('id');
只需在外键末尾添加->unsigned()->index()
即可。
如果您在外键定义中使用 ->onDelete('set null')
,请确保外键字段本身是 nullable()
即
//Column definition
$table->integer('user_id')->unsigned()->index()->nullable(); //index() is optional
//...
//...
//Foreign key
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('set null');
您应该按顺序创建迁移
例如,我希望我的 users
有一个来自 roles
table
的 role_id
字段
我先开始做我的角色迁移
php artisan make:migration create_roles_table --create=roles
然后我的第二次用户迁移
php artisan make:migration create_users_table --create=users
php artisan migration
将使用创建文件的顺序执行
2017_08_22_074128_create_roles_table.php 和 2017_08_22_134306_create_users_table 检查日期时间顺序,这将是执行顺序。
个文件
2017_08_22_074128_create_roles_table.php
public function up()
{
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 50);
$table->timestamps();
});
}
2017_08_22_134306_create_users_table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->integer('role_id')->unsigned();
$table->string('name');
$table->string('phone', 20)->unique();
$table->string('password');
$table->rememberToken();
$table->boolean('active');
$table->timestamps();
$table->foreign('role_id')->references('id')->on('roles');
});
}
请在您的字段中添加 ->nullable()
并确保您所指的所有字段都真实存在。
迁移文件的创建顺序应该排序并且外键应该与另一个table中的主键完全相似属性。
在我的例子中,新的 laravel 约定导致了这个错误。
只需简单交换 table 创建 id
就可以了。
$table->increments('id'); // ok
,而不是:
$table->bigIncrements('id'); // was the error.
已经在使用 Laravel v5.8
,以前从未出现过此错误。
在 Laravel 中创建新的 table 时。将生成如下迁移:
$table->bigIncrements('id');
而不是(在旧 Laravel 版本中):
$table->increments('id');
当使用 bigIncrements
时,外键需要 bigInteger 而不是 integer。所以您的代码将如下所示:
public function up()
{
Schema::create('meals', function (Blueprint $table) {
$table->increments('id');
$table->unsignedBigInteger('user_id'); //changed this line
$table->unsignedBigInteger('category_id'); //changed this line
$table->string('title');
$table->string('body');
$table->string('meal_av');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade');
});
}
您也可以使用 increments
而不是像 所说的 bigIncrements
。
Integer 和 BigInteger 的区别在于大小:
- 整数 => 32 位
- bigint => 64 位
请记住这一点很重要,引用字段和引用字段必须具有完全相同的数据类型。
我收到了关于数据类型不匹配问题的相同消息。
我将 bigIncrements() 用于 'id',当我将其用作外键时(使用 bigInteger())我得到了错误。
我找到了解决方案,bigIncrements() returns unsignedBigInteger。所以需要在外键
中使用unsignedBigInteger()而不是bigInteger()
分享这个可能对其他人有帮助
创建 "meals"
时应先创建类别和用户 Table
要解决此问题,您应该将类别和用户的迁移文件重命名为创建餐前迁移文件的日期 table。
样本:
2019_04_10_050958_create_users_table
2019_04_10_051958_create_categories_table
2019_04_10_052958_create_meals_table
Laravel 5.8
在外键列中使用 unsignedBigInteger 以避免外键数据类型不匹配的问题。例如,假设我们有两个 tables questions 和 replies
问题 table 看起来:
public function up()
{
Schema::create('questions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('body');
$table->integer('user_id')->unsigned();
$table->timestamps();
});
}
回复 table 看起来像:
public function up()
{
Schema::create('replies', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('body');
$table->unsignedBigInteger('question_id');
$table->integer('user_id')->unsigned();
$table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade');
$table->timestamps();
});
}
很简单的问题,简单回答一下,不要拐弯抹角,
将您的示例 $table->integer('user_id')->unsigned();
更改为 $table->BigInteger('user_id')->unsigned();
以解决外键错误。所以在迁移文件中将整数更改为 BigInteger...
解决外键错误的一种方法是禁用检查:"SET FOREIGN_KEY_CHECKS"。
这是一个治标不治本的办法,但真正正确的做法是调整表格及其关系。
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
Schema::table('example', function (Blueprint $table) {
$table->integer('fk_example')->unsigned()->index();
$table->foreign('fk_example')->references('id')->on('examples');
});
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
我只是用 $table->unsignedBigInteger('user_id'); 解决了。 (laravel 5.8)
Laravel 6:2020 年 1 月 17 日更新
$table->bigInteger( 'category_id' )->unsigned();
这对我来说效果很好
- 检查你的数据库引用table必须有主键&&自动递增
- 删除要迁移的 table,然后 运行 再次迁移
我不得不在 Laravel 6 遇到同样的问题。我通过以下方式解决这个问题。
我认为它对您或其他人有帮助:
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned(); //chnage this line
$table->bigInteger('category_id')->unsigned(); //change this line
---
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade');
Incrementing ID using a "big integer" equivalent.
used bigInteger instead of Integer
- 如果现在还是出错了。
我建议您按照以下方式重新排序您的迁移文件:
Change the dates that form the first part of the migration filenames
So they're in the order you want (example: for
2020_07_28_133303_update_categories.php, the date & time is
2020-07-28, 13:33:03);
N.B: First must be 'categories' migration file than 'meals' migration
File.
N.B:
在 Laravel 5.6,
对于 $table->increments('id')
;
使用 $table->integer('user_id')->unsigned();
我刚刚添加
$table->engine = 'MyISAM';
成功了。
这是因为 laravel 默认使用 InnoDB 引擎创建表。
我遇到了同样的问题,所以我更改了迁移的创建日期,更改了这个,我更改了迁移的执行顺序,并且首先创建了所需的 table table 我用它作为外键
就我而言,问题是 table 引擎之间的差异。在我引用的 table 中,我没有指定引擎。
没用
// Referenced table
Schema::create('budgets', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->softDeletes();
});
// The other table
Schema::create('payment', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('budget_id')->unsigned()->nullable();
$table->foreign('budget_id')
->references('id')
->on('budgets')
->onDelete('cascade');
$table->timestamps();
});
为了控制它,我建议在所有迁移上设置引擎以创建 tables。 (不要相信默认的数据库设置)
有效
// Referenced table
Schema::create('budgets', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->id();
$table->timestamps();
$table->softDeletes();
});
// The other table
Schema::create('payment', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('budget_id')->unsigned()->nullable();
$table->foreign('budget_id')
->references('id')
->on('budgets')
->onDelete('cascade');
$table->timestamps();
});
我正在使用 Laravel 8 并且遇到了同样的错误。问题是这两个列,例如 users.id 和 meals.user_id,其中 user_id 是外键需要相同。
users.id 看起来像这样:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
在 mySql 中,id 是 Int(10) 未签名的 AUTO ICREMENT。
如果我们转到另一个 table 我们想要设置外键的地方,例如下面的那个我也将 user_id 更改为 unsigned() 。以前我把它简单地写成 $table->integer('user_id')
,这给了我例外,但现在你不会遇到那个错误,因为它们都是 Int(10) 和 Unsigned:
Schema::create('users_permissions', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->integer('permission_id')->unsigned();
//Foreign Key Constraints
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');
//Setting the primary keys
$table->primary(['user_id','permission_id']);
});
您只需要按顺序创建迁移。确保首先创建不接收任何外键的表。然后创建那些做的。
如果您已经创建了迁移,只需更改迁移的时间或日期,这样那些不接收任何外键的表就会先于接收的表创建。
迁移我的数据库时,出现此错误。下面是我的代码,后面是我在尝试 运行 迁移时遇到的错误。
代码
public function up()
{
Schema::create('meals', function (Blueprint $table) {
$table->increments('id');
$table->integer('user_id')->unsigned();
$table->integer('category_id')->unsigned();
$table->string('title');
$table->string('body');
$table->string('meal_av');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade');
});
}
错误信息
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1005 Can't create tablemeal
.#sql-11d2_1 4
(errno: 150 "Foreign key constraint is incorrectly formed") (SQL: alter
tablemeals
add constraint meals_category_id_foreign foreign key (category_id
) referencescategories
(id
) on delete cascade)
@JuanBonnett 的
在我的例子中,问题是引用的表之一是 InnoDB,另一个是 MyISAM.
MyISAM 不支持外键关系。
所以,现在 两个 表都是 InnoDB。问题已解决。
必须自上而下创建迁移。
首先为 table 不属于任何人的人创建迁移。
然后为属于前一个的 table 创建迁移。
table 引擎问题的简化答案:
要为 table 设置存储引擎,请在架构构建器上设置引擎 属性:
Schema::create('users', function ($table) {
$table->engine = 'InnoDB';
$table->increments('id');
});
来自 Laravel 文档:https://laravel.com/docs/5.2/migrations
也许它对登陆这里的任何人都有帮助:我刚刚遇到了同样的问题,在我的情况下,我在外键约束之前的外键列上设置了一个(复合)唯一约束。我通过将 "unique" 语句放在 "foreign" 语句之后解决了这个问题。
作品:
$table->foreign('step_id')->references('id')->on('steps')->onDelete('cascade');
$table->unique(['step_id','lang']);
无效:
$table->unique(['step_id','lang']);
$table->foreign('step_id')->references('id')->on('steps')->onDelete('cascade');
对我来说,一切都按正确的顺序进行,但仍然无法正常工作。后来摸索发现主键必须是无符号的
//this didn't work
$table->integer('id')->unique();
$table->primary('id');
//this worked
$table->integer('id')->unsigned()->unique();
$table->primary('id');
//this worked
$table->increments('id');
只需在外键末尾添加->unsigned()->index()
即可。
如果您在外键定义中使用 ->onDelete('set null')
,请确保外键字段本身是 nullable()
即
//Column definition
$table->integer('user_id')->unsigned()->index()->nullable(); //index() is optional
//...
//...
//Foreign key
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('set null');
您应该按顺序创建迁移
例如,我希望我的 users
有一个来自 roles
table
role_id
字段
我先开始做我的角色迁移
php artisan make:migration create_roles_table --create=roles
然后我的第二次用户迁移
php artisan make:migration create_users_table --create=users
php artisan migration
将使用创建文件的顺序执行
2017_08_22_074128_create_roles_table.php 和 2017_08_22_134306_create_users_table 检查日期时间顺序,这将是执行顺序。
个文件 2017_08_22_074128_create_roles_table.php
public function up()
{
Schema::create('roles', function (Blueprint $table) {
$table->increments('id');
$table->string('name', 50);
$table->timestamps();
});
}
2017_08_22_134306_create_users_table
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->integer('role_id')->unsigned();
$table->string('name');
$table->string('phone', 20)->unique();
$table->string('password');
$table->rememberToken();
$table->boolean('active');
$table->timestamps();
$table->foreign('role_id')->references('id')->on('roles');
});
}
请在您的字段中添加 ->nullable()
并确保您所指的所有字段都真实存在。
迁移文件的创建顺序应该排序并且外键应该与另一个table中的主键完全相似属性。
在我的例子中,新的 laravel 约定导致了这个错误。
只需简单交换 table 创建 id
就可以了。
$table->increments('id'); // ok
,而不是:
$table->bigIncrements('id'); // was the error.
已经在使用 Laravel v5.8
,以前从未出现过此错误。
在 Laravel 中创建新的 table 时。将生成如下迁移:
$table->bigIncrements('id');
而不是(在旧 Laravel 版本中):
$table->increments('id');
当使用 bigIncrements
时,外键需要 bigInteger 而不是 integer。所以您的代码将如下所示:
public function up()
{
Schema::create('meals', function (Blueprint $table) {
$table->increments('id');
$table->unsignedBigInteger('user_id'); //changed this line
$table->unsignedBigInteger('category_id'); //changed this line
$table->string('title');
$table->string('body');
$table->string('meal_av');
$table->timestamps();
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade');
});
}
您也可以使用 increments
而不是像 bigIncrements
。
Integer 和 BigInteger 的区别在于大小:
- 整数 => 32 位
- bigint => 64 位
请记住这一点很重要,引用字段和引用字段必须具有完全相同的数据类型。
我收到了关于数据类型不匹配问题的相同消息。
我将 bigIncrements() 用于 'id',当我将其用作外键时(使用 bigInteger())我得到了错误。
我找到了解决方案,bigIncrements() returns unsignedBigInteger。所以需要在外键
中使用unsignedBigInteger()而不是bigInteger()分享这个可能对其他人有帮助
创建 "meals"
时应先创建类别和用户 Table要解决此问题,您应该将类别和用户的迁移文件重命名为创建餐前迁移文件的日期 table。
样本:
2019_04_10_050958_create_users_table
2019_04_10_051958_create_categories_table
2019_04_10_052958_create_meals_table
Laravel 5.8
在外键列中使用 unsignedBigInteger 以避免外键数据类型不匹配的问题。例如,假设我们有两个 tables questions 和 replies
问题 table 看起来:
public function up()
{
Schema::create('questions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('body');
$table->integer('user_id')->unsigned();
$table->timestamps();
});
}
回复 table 看起来像:
public function up()
{
Schema::create('replies', function (Blueprint $table) {
$table->bigIncrements('id');
$table->text('body');
$table->unsignedBigInteger('question_id');
$table->integer('user_id')->unsigned();
$table->foreign('question_id')->references('id')->on('questions')->onDelete('cascade');
$table->timestamps();
});
}
很简单的问题,简单回答一下,不要拐弯抹角,
将您的示例 $table->integer('user_id')->unsigned();
更改为 $table->BigInteger('user_id')->unsigned();
以解决外键错误。所以在迁移文件中将整数更改为 BigInteger...
解决外键错误的一种方法是禁用检查:"SET FOREIGN_KEY_CHECKS"。 这是一个治标不治本的办法,但真正正确的做法是调整表格及其关系。
DB::statement('SET FOREIGN_KEY_CHECKS=0;');
Schema::table('example', function (Blueprint $table) {
$table->integer('fk_example')->unsigned()->index();
$table->foreign('fk_example')->references('id')->on('examples');
});
DB::statement('SET FOREIGN_KEY_CHECKS=1;');
我只是用 $table->unsignedBigInteger('user_id'); 解决了。 (laravel 5.8)
Laravel 6:2020 年 1 月 17 日更新
$table->bigInteger( 'category_id' )->unsigned();
这对我来说效果很好
- 检查你的数据库引用table必须有主键&&自动递增
- 删除要迁移的 table,然后 运行 再次迁移
我不得不在 Laravel 6 遇到同样的问题。我通过以下方式解决这个问题。
我认为它对您或其他人有帮助:
$table->bigIncrements('id');
$table->bigInteger('user_id')->unsigned(); //chnage this line
$table->bigInteger('category_id')->unsigned(); //change this line
---
$table->foreign('user_id')
->references('id')
->on('users')
->onDelete('cascade');
$table->foreign('category_id')
->references('id')
->on('categories')
->onDelete('cascade');
Incrementing ID using a "big integer" equivalent.
used bigInteger instead of Integer
- 如果现在还是出错了。
我建议您按照以下方式重新排序您的迁移文件:
Change the dates that form the first part of the migration filenames So they're in the order you want (example: for 2020_07_28_133303_update_categories.php, the date & time is 2020-07-28, 13:33:03);
N.B: First must be 'categories' migration file than 'meals' migration File.
N.B:
在 Laravel 5.6,
对于 $table->increments('id')
;
使用 $table->integer('user_id')->unsigned();
我刚刚添加
$table->engine = 'MyISAM';
成功了。 这是因为 laravel 默认使用 InnoDB 引擎创建表。
我遇到了同样的问题,所以我更改了迁移的创建日期,更改了这个,我更改了迁移的执行顺序,并且首先创建了所需的 table table 我用它作为外键
就我而言,问题是 table 引擎之间的差异。在我引用的 table 中,我没有指定引擎。
没用
// Referenced table
Schema::create('budgets', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->softDeletes();
});
// The other table
Schema::create('payment', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('budget_id')->unsigned()->nullable();
$table->foreign('budget_id')
->references('id')
->on('budgets')
->onDelete('cascade');
$table->timestamps();
});
为了控制它,我建议在所有迁移上设置引擎以创建 tables。 (不要相信默认的数据库设置)
有效
// Referenced table
Schema::create('budgets', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->id();
$table->timestamps();
$table->softDeletes();
});
// The other table
Schema::create('payment', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->integer('budget_id')->unsigned()->nullable();
$table->foreign('budget_id')
->references('id')
->on('budgets')
->onDelete('cascade');
$table->timestamps();
});
我正在使用 Laravel 8 并且遇到了同样的错误。问题是这两个列,例如 users.id 和 meals.user_id,其中 user_id 是外键需要相同。
users.id 看起来像这样:
Schema::create('users', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
在 mySql 中,id 是 Int(10) 未签名的 AUTO ICREMENT。
如果我们转到另一个 table 我们想要设置外键的地方,例如下面的那个我也将 user_id 更改为 unsigned() 。以前我把它简单地写成 $table->integer('user_id')
,这给了我例外,但现在你不会遇到那个错误,因为它们都是 Int(10) 和 Unsigned:
Schema::create('users_permissions', function (Blueprint $table) {
$table->integer('user_id')->unsigned();
$table->integer('permission_id')->unsigned();
//Foreign Key Constraints
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->foreign('permission_id')->references('id')->on('permissions')->onDelete('cascade');
//Setting the primary keys
$table->primary(['user_id','permission_id']);
});
您只需要按顺序创建迁移。确保首先创建不接收任何外键的表。然后创建那些做的。 如果您已经创建了迁移,只需更改迁移的时间或日期,这样那些不接收任何外键的表就会先于接收的表创建。