迁移:不能添加外键约束

我试图在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_projectproject_tasks等。

希望有人能帮我开始。

311862 次浏览

分两步添加它,最好让它也是无符号的:

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';

这个错误发生在我,因为-当我试图创建的表是InnoDB -外表,我试图将它关联到一个MyISAM表!

在我的例子中,问题是主表中已经有记录,我强制新列不为NULL。因此,在新列中添加->nullable()就成功了。在这个问题的例子中是这样的:

$table->integer('user_id')->unsigned()->nullable();

或者:

$table->unsignedInteger('user_id')->nullable();

希望这能帮助到一些人!

在我的例子中,我引用了字符串 user_id列上的整数 id列。我改变了:

$table->string('user_id')

:

$table->integer('user_id')->unsigned();

希望它能帮助到一些人!

为了在laravel中添加外键约束,我使用了以下方法:

  1. 按如下方式创建外键列:

    $table->integer('column_name')->unsigned();
  2. Adding the constraint line immediately after (1) i.e.

    $table->integer('column_name')->unsigned();
    $table->foreign('column_name')->references('pk_of_other_table')->on('other_table');

在我的案例中,问题在于迁移时机,在创建迁移时要小心,首先创建子迁移,而不是基础迁移。因为如果你先创建base migration,有外键就会寻找子表,不会有抛出异常的表。

进一步:

当您创建迁移时,它的开头有一个时间戳。假设你已经创建了一个迁移,所以它看起来像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工匠迁移。它会抛出一个异常,因为迁移会首先在你的数据库中创建基表因为你先创建了这个迁移,我们的基表有外键约束,它会寻找子表,而子表不存在,这可能是一个异常。

所以:

首先创建子表迁移。

在创建子迁移之后创建基表迁移。

PHP工匠迁移。

做就行了

我们不能添加关系,除非创建了相关的表。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');
});

我认为这里的答案中遗漏了一件事,如果我错了请纠正我,但是外键需要在数据透视表中被索引。至少在mysql中是这样的。

public function up()
{
Schema::create('image_post', function (Blueprint $table) {
$table->engine = 'InnoDB';
$table->increments('id');
$table->integer('image_id')->unsigned()->index();
$table->integer('post_id')->unsigned()->index();
$table->timestamps();
});


Schema::table('image_post', function($table) {
$table->foreign('image_id')->references('id')->on('image')->onDelete('cascade');
$table->foreign('post_id')->references('id')->on('post')->onDelete('cascade');
});


}

在最初的问题之后的几年,我使用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');
}

产品表:首先需要迁移这个表。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_9999_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');
//        });

我用Laravel 5做数据透视表时也犯了同样的错误,我的问题是我没有

->onDelete('cascade');

我知道这是一个老问题,但确保如果你使用的是引用,正确的支持引擎是定义的。为两个表设置innodb引擎,为参考列设置相同的数据类型

$table->engine = 'InnoDB';

这么简单!!

如果你第一次创建'priorities'迁移文件,Laravel首先运行'priorities',而'users'表不存在。

它如何向一个不存在的表添加关系!

解决方案:退出 外键代码'priorities'表。你的迁移文件应该是这样的:

enter image description here

并添加到一个新的迁移文件中,这里它的名字是create_prioritiesForeignKey_table,并添加这些代码:

public function up()
{
Schema::table('priorities', function (Blueprint $table) {
$table->foreign('user_id')
->references('id')
->on('users');
});
}

使用Laravel 5.3也有同样的问题。

解决方案是使用unsignedInteger而不是整数(“名字”)- >无符号()

这就是有效的方法

$table->unsignedInt('column_name');
$table->foreign('column_name')->references('id')->on('table_name');

这样做的原因是,当使用整数(“名字”)- >无符号时,在表中创建的列的长度为11,但当使用unsigedInteger(“名字”)时,列的长度为10。

长度10是使用Laravel时主键的长度,因此列的长度匹配。

其要点是,外部方法使用ALTER_TABLE将一个预先存在的字段变成外键。所以在应用外键之前必须定义表类型。然而,它不必在一个单独的Schema::调用中。你可以在create中做这两件事,像这样:

public function up()
{
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});
}

还要注意,user_id的类型被设置为unsigned以匹配外键。

在我的情况下,我只是改变了手动执行迁移的顺序,因此首先创建表用户。

在文件夹database/migrations/你的迁移文件名有这样的格式: year_month_day_hhmmss_create_XXXX_table.php < / p >

只是重命名创建用户文件,这样你的表优先级表的创建日期设置晚于用户日期(甚至晚一秒就足够了)

我认为:参考键必须是index。 例如:(下降)< / p >

public function up()
{
Schema::create('clicks', function (Blueprint $table) {
$table->increments('id');
$table->string('viewer_id');
$table->integer('link_id')->index()->unsigned();
$table->string('time');
$table->timestamps();
});


Schema::table('clicks', function($table) {
$table->foreign('link_id')->references('id')->on('links')->onDelete('cascade');
});




}

祝你好运。

确保你的外分栏超过外分键栏的宽范围

我的意思是你的前键(在第二个表)必须是相同类型的你的ponter主键(在第一个表)

您的指针主键必须添加unsigned方法,让我显示:

在你的第一个迁移表上:

$table->increments('column_name'); //is INTEGER and UNSIGNED

在第二个迁移表上:

$table->integer('column_forein_name')->unsigned(); //this must be INTEGER and UNSIGNED
$table->foreign('column_forein_name')->references('column_name')->on('first_table_name');

另一个例子可以看出区别

在你的第一个迁移表上:

$table->mediumIncrements('column_name'); //is MEDIUM-INTEGER and UNSIGNED

在第二个迁移表上:

$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 .

你可以直接在整型列中传递布尔参数,说它是否应该是无符号的。在laravel 5.4下面的代码解决了我的问题。

        $table->integer('user_id', false, true);

这里第二个参数表示它不应该是自动递增的,第三个参数真正的表示它应该是无符号的。可以将外键约束保留在同一迁移中,也可以将其分离。两者都适用。

如果以上解决方案对新手都不起作用,检查两个id是否具有相同的类型:都是integer或都是bigInteger,…你可以有这样的东西:

主表(例如用户)

$table->bigIncrements('id');

子表(例如优先级)

$table->unsignedInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

此查询将失败,因为__ABC0是__ABC1,而__ABC2是INTEGER

在这种情况下,正确的查询如下:

$table->unsignedBigInteger('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

在我的情况下,直到我运行命令它才工作

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

目录

注意:当Laravel设置一个表使用

$table->increments('id');

这在大多数迁移中是标准的,这将设置一个无符号整数字段。因此,当从另一个表对这个字段进行外部引用时,确保在引用表中,您将字段设置为UnsignedBigInteger,而不是(我假设是一个)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');
}

在我的例子中,问题是正在设置users表的自动生成迁移

...
$table->bigIncrements('id');
...

所以我必须改变列的类型


$table->bigInteger('id');

使我的迁移与外键工作。

这与laravel 5.8.2

对于我来说,我的子表引用的表列没有被索引。

Schema::create('schools', function (Blueprint $table) {
$table->integer('dcid')->index()->unque();
$table->integer('school_number')->index(); // The important thing is that this is indexed
$table->string('name');
$table->string('abbreviation');
$table->integer('high_grade');
$table->integer('low_grade');
$table->timestamps();
$table->primary('dcid');
});


Schema::create('students', function (Blueprint $table) {
$table->increments('id');
$table->integer('dcid')->index()->unique()->nullable();
$table->unsignedInteger('student_number')->nullable();
$table->integer('schoolid')->nullable();
$table->foreign('schoolid')->references('school_number')->on('schools')->onDelete('set null');
// ...
});

忽略这个糟糕的命名,它来自另一个设计糟糕的系统。

在仔细研究了laravel文档后,我在使用Laravel 5.8。时也遇到了同样的问题。我解决这个问题的方法是将主键“表- > bigIncrements (id)”添加到与表“用户”及其关联相关的每个表中,在我的例子中是表“角色”。最后,我有“表- > 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']);
});

Laravel ^ 5.8

从Laravel 5.8开始,迁移存根在ID上使用bigIncrements方法 列。方法创建ID列 增量方法。< / p > 这不会影响项目中任何现有的代码;然而,是 意识到外键列必须是同一类型。因此,一个 使用increments方法无法参考创建的列

. bigIncrements方法创建

来源:Migrations &bigIncrements < / >


例子

假设你正在构建一个简单的基于角色的应用程序,你需要在“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');
});
}

正如你所看到的,被注释的行会抛出一个查询异常,因为,正如升级说明中提到的,外键列的类型必须相同,因此你需要在role_user表中将前键(在本例中是user_id)更改为bigInteger,或者在用户表中将bigIncrements方法更改为增量方法,并在透视表中使用被注释的行,这取决于你。


我希望我能向你澄清这个问题。

我注意到的一件事是,如果表使用不同的引擎比外键约束不起作用。

例如,如果一个表使用:

$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
});
}

在laravel 5.8中,users_table使用bigIncrements('id')数据类型作为主键。因此,当你想引用一个外键约束时,你的user_id列需要是unsignedBigInteger('user_id')类型。

你应该这样写

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 5.8中有这个问题,我修复了这段代码,如在Laravel文档中所示,无论我在哪里添加外键。

$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');
});

有时这种错误可能是由于迁移的顺序造成的。

Users和Order是两个表

订单表中有用户的外键 (在迁移过程中,如果Order表先迁移,则会导致问题,因为没有用户匹配外键)

< p >解决方案: 只需将您的Order Update表放在用户下面Update

< p >的例子: 在我的例子中,教育和大学表 教育表< / p >
public function up()
{
Schema::create('doc_education', function (Blueprint $table) {
$table->increments('id');
$table->integer('uni_id')->unsigned()->nullable();
$table->timestamps();
});
}

在大学里

    Schema::create('doc_universties', function (Blueprint $table) {
$table->increments('id');
$table->string('uni_name');
$table->string('location')->nullable();
$table->timestamps();


//
});






Schema::table('doc_education', function(Blueprint $table) {
$table->foreign('uni_id')->references('id')
->on('doc_universties')->onDelete('cascade');
});

对我来说,问题是旧表使用MyISAM而不是InnoDB。这就解决了问题

    $tables = [
'table_1',
'table_2'
];


foreach ($tables as $table) {
\DB::statement('ALTER TABLE ' . $table . ' ENGINE = InnoDB');
}

(学习英语,抱歉) 我试着在我的项目中使用“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');
});
}

IMPORTANTE:在本例中,首先创建没有外键的表"user "表格

另一个原因可能是DB引擎类型。Laravel默认使用MyISAM引擎。所以如果你需要强制外键引用检查,你应该使用InnoDB作为你的引擎。

这个设置在你的config/database.php文件中。将引擎更改为'engine' => 'InnoDB'

另外,如果您试图对现有表执行此操作,请使用

DB::statement("ALTER TABLE `{$tableName}` ENGINE = 'InnoDB'");

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');

请先检查列的数据类型。如果第一个表的id类型是bigint,那么当添加外键时,检查其他表的类型应该是bigint。

在自动创建的create_users_table迁移中,将$table->id();改为$table->increments('id');。为我做了这个技巧,希望这对你有帮助!

快捷的解决方案:

/ /内部模式::创建

表→美元外国(user_id)→bigInteger (user_id)→无符号()→指数();

/ /内部模式::表

$table->foreign('users_id')->references('id')->on('users')->onUpdate('cascade')->onDelete('cascade');

//正在编写代码。

public function up()
{
//
Schema::create('priorities', function($table) {
$table->increments('id', true);
$table->integer('user_id');
$table->foreign('user_id')->bigInteger('user_id')->unsigned()->index();
  

$table->string('priority_name');
$table->smallInteger('rank');
$table->text('class');
$table->timestamps('timecreated');
});


Schema::table('administrador', function($table) {
$table->foreign('users_id')->references('id')->on('users')
->onUpdate('cascade')
->onDelete('cascade');
;
});


}

上面所有的解决方案都是正确的,但没有一个适合我。< Br >

为我创造问题的东西是数据库表引擎。引擎类型已经添加的表是MyISAM和新的migration正在设置engine type = 'InnoDB'

我只是将已经添加的表的Engine Type设置为InnoDB,就是这样!

enter image description here