我正在尝试在 Laravel 中创建外键,但是当我使用 artisan
迁移我的表时,我抛出了以下错误:
[Illuminate\Database\QueryException]
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint (SQL
: alter table `priorities` add constraint priorities_user_id_foreign foreign
key (`user_id`) references `users` (`id`))
我的迁移代码是这样的:
优先级迁移文件
public function up()
{
//
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::drop('priorities');
}
用户迁移文件
public function up()
{
//
Schema::table('users', function($table)
{
$table->create();
$table->increments('id');
$table->string('email');
$table->string('first_name');
$table->string('password');
$table->string('email_code');
$table->string('time_created');
$table->string('ip');
$table->string('confirmed');
$table->string('user_role');
$table->string('salt');
$table->string('last_login');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schemea::drop('users');
}
关于我做错了什么的任何想法,我现在想得到这个,因为我有很多需要创建的表,例如用户、客户、项目、任务、状态、优先级、类型、团队。理想情况下,我想创建使用外键保存这些数据的表,即 clients_project
和 project_tasks
等。
希望有人可以帮助我开始。
分两步添加,也可以让它无符号:
public function up()
{
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id')->unsigned();
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
Schema::table('priorities', function($table) {
$table->foreign('user_id')->references('id')->on('users');
});
}
问题已经回答,但希望这可能对其他人有所帮助。
发生此错误是因为我首先在其中创建了带有外键的迁移表,然后该键作为原始表中的主键存在。迁移按照它们创建的顺序执行,如运行 migrate:make
后生成的文件名所示。例如2014_05_10_165709_create_student_table.php
。
解决方案是将具有外键的文件重命名为比具有此处建议的主键的文件更早的时间:http://forumsarchive.laravel.io/viewtopic.php?id=10246
我想我还必须添加 $table->engine = 'InnoDB';
Laravel ^5.8
从 Laravel 5.8 开始,迁移存根默认对 ID 列使用 bigIncrements 方法。以前,ID 列是使用增量方法创建的。这不会影响您项目中的任何现有代码;但是,请注意外键列的类型必须相同。因此,使用 increments 方法创建的列不能引用使用 bigIncrements 方法创建的列。资料来源:迁移和大增量
例子
假设您正在构建一个简单的基于角色的应用程序,并且您需要引用 PIVOT 表“role_user”中的 user_id。
2019_05_05_112458_create_users_table.php
// ...
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('full_name');
$table->string('email');
$table->timestamps();
});
}
2019_05_05_120634_create_role_user_pivot_table.php
// ...
public function up()
{
Schema::create('role_user', function (Blueprint $table) {
// this line throw QueryException "SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint..."
// $table->integer('user_id')->unsigned()->index();
$table->bigInteger('user_id')->unsigned()->index(); // this is working
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
});
}
如您所见,注释行将引发查询异常,因为如升级说明中所述,外键列必须是相同类型,因此您需要将外键(在本例中为 user_id)更改为role_user 表中的 bigInteger 或将 bigIncrements 方法更改为 users 表中的增量方法并使用数据透视表中的注释行,这取决于您。
我希望我能够向你澄清这个问题。
Schema::table('goal_objective', function (Blueprint $table) { $table->bigInteger('job_title_id')->after('target')->unsigned()->nullable(); $table->foreign('job_title_id')->references('id')->on('job_titles')->onDelete('set null'); }
它奏效了。谢谢你。
就我而言,问题是主表中已经有记录,我强制新列不为 NULL。因此,将 ->nullable() 添加到新列就可以了。在问题的示例中将是这样的:
$table->integer('user_id')->unsigned()->nullable();
或者:
$table->unsignedInteger('user_id')->nullable();
希望这对某人有帮助!
onUpdate("SET NULL")
或 onDelete("SET NULL")
设置为外部 id 时,这一点也非常重要
在我的情况下,问题是 users
表的自动生成迁移正在设置
...
$table->bigIncrements('id');
...
所以我不得不改变列类型
$table->bigInteger('id');
使我的外键迁移工作。
这与 laravel 5.8.2
在我的情况下,问题在于迁移时间要小心,同时创建迁移首先创建子迁移而不是基本迁移。因为如果您首先创建具有外键的基本迁移,则会查找子表,并且不会有然后抛出异常的表。
此外:
当您创建迁移时,它的开头有一个时间戳。假设您创建了一个迁移 cat,所以它看起来像 2015_08_19_075954_the_cats_time.php
并且它有这个代码
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class TheCatsTime extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('cat', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->date('date_of_birth');
$table->integer('breed_id')->unsigned()->nullable();
});
Schema::table('cat', function($table) {
$table->foreign('breed_id')->references('id')->on('breed');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('cat');
}
}
在创建基表之后,您将创建另一个迁移品种,它是子表,它有自己的创建时间和日期戳。代码将如下所示:
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class BreedTime extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('breed', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('breed');
}
}
似乎这两个表都是正确的,但是当您运行 php artisan migrate 时。它将引发异常,因为迁移将首先在您的数据库中创建基表,因为您首先创建了此迁移,并且我们的基表中有外键约束,它将查找子表并且子表不存在,这可能是一个例外。。
所以:
先创建子表迁移。创建子迁移后创建基表迁移。 php工匠迁移。
完成它会工作
在 laravel 5.8 中,users_table 使用 bigIncrements('id')
数据类型作为主键。因此,当您要引用外键约束时,您的 user_id
列需要是 unsignedBigInteger('user_id')
类型。
我在 laravel 5.8 中遇到了这个问题,我修复了这个代码,如图 here in Laravel documentation 所示,在我添加外键的地方。
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
然后我跑了$ php artisan migrate:refresh
由于这种语法相当冗长,Laravel 提供了额外的、更简洁的方法,这些方法使用约定来提供更好的开发者体验。上面的例子可以这样写:
Schema::table('posts', function (Blueprint $table) {
$table->foreignId('user_id')->constrained()->onDelete('cascade');
});
就我而言,我只是更改了手动执行迁移的顺序,因此首先创建了表用户。
在文件夹 database/migrations/ 您的迁移文件名具有以下格式:year_month_day_hhmmss_create_XXXX_table.php
只需重命名创建用户文件,以便将表优先级表的创建日期设置为晚于用户日期(即使晚一秒就足够了)
我在使用 Laravel 5.8 时遇到了同样的问题。 在仔细查看了 laravel 文档之后,这里还有 Migrations & bigIncrements。我解决它的方法是将主键 "$table->bigIncrements('id')" 添加到与表 "users" 相关的每个表中及其关联,在我的例子中是表“role”。最后,我有 "$table->unsignedBigInteger" 用于将角色与用户关联(多对多),即表 "role_user"。
1. Users table
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
2. Roles Table
Schema::create('roles', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name')->unique();
$table->string('display_name')->nullable();
$table->string('description')->nullable();
$table->timestamps();
});
3. Table role_user
Schema::create('role_user', function (Blueprint $table) {
$table->unsignedBigInteger('user_id');
$table->unsignedBigInteger('role_id');
$table->foreign('user_id')->references('id')->on('users')
->onUpdate('cascade')->onDelete('cascade');
$table->foreign('role_id')->references('id')->on('roles')
->onUpdate('cascade')->onDelete('cascade');
$table->primary(['user_id', 'role_id']);
});
这个错误发生在我身上,因为 - 虽然我试图创建的表是 InnoDB - 我试图将其关联的外部表是 MyISAM 表!
使用 Laravel 5.3 也有同样的问题。
解决方案是使用 unsignedInteger 而不是 integer('name')->unsigned()。
所以这就是有效的
$table->unsignedInt('column_name');
$table->foreign('column_name')->references('id')->on('table_name');
这样做的原因是,当使用 integer('name')->unsigned 时,在表中创建的列的长度为 11,但当使用 unsigedInteger('name') 时,列的长度为 10。
长度 10 是使用 Laravel 时主键的长度,因此列长度匹配。
我们无法添加关系,除非创建了相关表。 Laravel 按迁移文件的日期顺序运行迁移。因此,如果您想与第二个迁移文件中存在的表创建关系,它会失败。
我遇到了同样的问题,所以我最后又创建了一个迁移文件来指定所有关系。
Schema::table('properties', function(Blueprint $table) {
$table->foreign('user')->references('id')->on('users')->onDelete('cascade');
$table->foreign('area')->references('id')->on('areas')->onDelete('cascade');
$table->foreign('city')->references('id')->on('cities')->onDelete('cascade');
$table->foreign('type')->references('id')->on('property_types')->onDelete('cascade');
});
Schema::table('areas', function(Blueprint $table) {
$table->foreign('city_id')->references('id')->on('cities')->onDelete('cascade');
});
你应该这样写
public function up()
{
Schema::create('transactions', function (Blueprint $table) {
$table->bigIncrements('id');
$table->float('amount', 11, 2);
$table->enum('transaction type', ['debit', 'credit']);
$table->bigInteger('customer_id')->unsigned();
$table->timestamps();
});
Schema::table('transactions', function($table) {
$table->foreign('customer_id')
->references('id')->on('customers')
->onDelete('cascade');
});
}
外键字段应该是无符号的,希望有帮助!!
为了在 laravel 中添加外键约束,以下内容对我有用:
创建列作为外键如下: $table->integer('column_name')->unsigned();在 (1) 之后立即添加约束行,即 $table->integer('column_name')->unsigned(); $table->foreign('column_name')->references('pk_of_other_table')->on('other_table');
注意:当 Laravel 使用
$table->increments('id');
这是大多数迁移的标准,这将设置一个无符号整数字段。因此,当从另一个表对该字段进行外部引用时,请确保在引用表中将该字段设置为 UnsignedInteger 而不是(我假设是)UnsignedBigInteger 字段。
例如:在迁移文件 2018_12_12_123456_create_users_table.php 中:
Schema::create('users', function (Blueprint $table){
$table->increments('id');
$table->string('name');
$table->timestamps();
然后在迁移文件 2018_12_12_18000000_create_permissions_table.php 中,将外部引用设置回用户:
Schema::create('permissions', function (Blueprint $table){
$table->increments('id');
$table->UnsignedInteger('user_id'); // UnsignedInteger = "increments" in users table
$table->boolean('admin');
$table->boolean('enabled');
$table->timestamps();
// set up relationship
$table->foreign('user_id')->reference('id')->on('users')->onDelete('cascade');
}
2021 年 4 月 20 日
在 Laravel 8 中,我遇到了这个问题。如果您不使用 nullable()
,则可能会发生此错误。
$table->bigInteger('user_id')->nullable()->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('set null');
我知道这是一个老问题,但请确保您是否正在使用参考资料,并定义了正确的支持引擎。为两个表设置innodb引擎,为引用列设置相同的数据类型
$table->engine = 'InnoDB';
如果上述解决方案都不适用于新手,请检查两个 ID 是否具有相同的类型:两者都是 integer
或两者都是 bigInteger
,......你可以有这样的事情:
主表(例如用户)
$table->bigIncrements('id');
子表(例如优先级)
$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
此查询将失败,因为 users.id
是 BIG INTEGER
而 priorities.user_id
是 INTEGER
。
在这种情况下,正确的查询如下:
$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
我注意到的一件事是,如果表使用与外键约束不同的引擎,则不起作用。
例如,如果一张表使用:
$table->engine = 'InnoDB';
以及其他用途
$table->engine = 'MyISAM';
会产生错误:
SQLSTATE[HY000]: General error: 1215 Cannot add foreign key constraint
您可以通过在表创建结束时添加 InnoDB 来解决此问题,如下所示:
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->unsignedInteger('business_unit_id')->nullable();
$table->string('name', 100);
$table->foreign('business_unit_id')
->references('id')
->on('business_units')
->onDelete('cascade');
$table->timestamps();
$table->softDeletes();
$table->engine = 'InnoDB'; # <=== see this line
});
}
(学习英语,抱歉)我在我的项目中尝试使用“foreignId”并且可以工作。在您的代码中只是删除列 user_id 并在参考上添加 foreignId :
public function up()
{
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->foreignId('user_id')->references('id')->on('users');
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
}
重要提示:首先在这种情况下创建没有外键的表“用户”表
在最初的问题发生几年后,在这里使用 laravel 5.1,我遇到了同样的错误,因为我的迁移是使用所有相同的日期代码计算机生成的。我浏览了所有建议的解决方案,然后重构以找到错误源。
在关注 laracast 和阅读这些帖子时,我相信正确的答案类似于 Vickies 的答案,只是您不需要添加单独的模式调用。您不需要将表设置为 Innodb,我假设 laravel 现在正在这样做。
迁移只需要正确计时,这意味着您将在需要外键的表的文件名中修改日期代码(稍后)。或者或另外,降低不需要外键的表的日期代码。
修改日期代码的好处是您的迁移代码将更易于阅读和维护。
到目前为止,我的代码正在通过调整时间码来推回需要外键的迁移。
但是我确实有数百个表,所以最后我有一个仅用于外键的表。只是为了让事情顺利进行。我假设我会将它们拉入正确的文件并在测试它们时修改日期代码。
举个例子:文件 2016_01_18_999999_create_product_options_table。这需要创建产品表。查看文件名。
public function up()
{
Schema::create('product_options', function (Blueprint $table) {
$table->increments('id');
$table->integer('product_attribute_id')->unsigned()->index();
$table->integer('product_id')->unsigned()->index();
$table->string('value', 40)->default('');
$table->timestamps();
//$table->foreign('product_id')->references('id')->on('products');
$table->foreign('product_attribute_id')->references('id')->on('product_attributes');
$table->foreign('product_id')->references('id')->on('products');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('product_options');
}
products 表:这需要先迁移。 2015_01_18_000000_create_products_table
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('style_number', 64)->default('');
$table->string('title')->default('');
$table->text('overview')->nullable();
$table->text('description')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('products');
}
最后是我临时用来解决问题的文件,我将在为我命名为 9999_99_99_999999_create_foreign_keys.php 的模型编写测试时重构该文件。当我把它们拔出来时,这些键被评论了,但你明白了。
public function up()
{
// Schema::table('product_skus', function ($table) {
// $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
// });
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
// Schema::table('product_skus', function ($table)
// {
// $table->dropForeign('product_skus_product_id_foreign');
// });
很简单 !!!
如果您第一次创建 'priorities'
迁移文件,Laravel 首先运行 'priorities'
而 'users'
表不存在。
它如何向不存在的表添加关系!。
解决方案:从 'priorities'
表中拉出 外键码。你的迁移文件应该是这样的:
https://i.stack.imgur.com/NaxAD.jpg
并添加到一个新的迁移文件,这里它的名称是 create_prioritiesForeignKey_table
并添加以下代码:
public function up()
{
Schema::table('priorities', function (Blueprint $table) {
$table->foreign('user_id')
->references('id')
->on('users');
});
}
确保您的外键列超出外键列的范围
我的意思是您的外键(在第二个表中)必须与您的 ponter 密钥(在第一个表中)相同类型
您的指针主键必须添加无符号方法,让我展示一下:
在您的 FIRST 迁移表上:
$table->increments('column_name'); //is INTEGER and UNSIGNED
在您的 SECOND 迁移表上:
$table->integer('column_forein_name')->unsigned(); //this must be INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');
另一个看到差异的例子
在您的 FIRST 迁移表上:
$table->mediumIncrements('column_name'); //is MEDIUM-INTEGER and UNSIGNED
在您的 SECOND 迁移表上:
$table->mediumInteger('column_forein_name')->unsigned(); //this must be MEDIUM-INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');
SEE MYSQL NUMERIC TYPES TABLE RANGES
在我的情况下,直到我运行命令它才起作用
composer dump-autoload
这样您就可以将外键留在 create Schema 中
public function up()
{
//
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id');
$table->foreign('user_id')->references('id')->on('users');
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
Schema::drop('priorities');
}
它也可能是您创建迁移的命令。如果你先创建优先级表,然后再创建用户表,那就错了。因为第一次迁移正在寻找用户表。所以,你必须改变迁移的顺序
app/database/migrations
目录
对我来说,问题是旧表使用的是 MyISAM 而不是 InnoDB。这修复了它
$tables = [
'table_1',
'table_2'
];
foreach ($tables as $table) {
\DB::statement('ALTER TABLE ' . $table . ' ENGINE = InnoDB');
}
另一个原因可能是数据库引擎类型。 Laravel 默认使用 MyISAM 引擎。所以如果你需要强制执行外键引用检查,你应该使用 InnoDB 作为你的引擎。
此设置位于您的 config/database.php
文件中。将引擎更改为 'engine' => 'InnoDB'
此外,如果您尝试对现有表执行此操作,请使用更改引擎
DB::statement("ALTER TABLE `{$tableName}` ENGINE = 'InnoDB'");
在自动创建的 create_users_table 迁移中,将 $table->id();
更改为 $table->increments('id');
。为我做了诀窍,希望这有帮助!
在我的例子中,我在 string user_id
列上引用了一个 integer id
列。我变了:
$table->string('user_id')
至:
$table->integer('user_id')->unsigned();
希望它可以帮助某人!
不定期副业成功案例分享
Schema::table
方法帮助!谢谢!bigIncrements
,请使用$table->unsignedBigInteger('user_id')