Laravel 迁移:“外键约束格式不正确”(errno 150)

Posted

技术标签:

【中文标题】Laravel 迁移:“外键约束格式不正确”(errno 150)【英文标题】:Laravel migration: "Foreign key constraint is incorrectly formed" (errno 150) 【发布时间】:2015-12-16 15:46:36 【问题描述】:

迁移我的数据库时,出现此错误。下面是我的代码,后面是我在尝试运行迁移时遇到的错误。

代码

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

错误信息

[照亮\数据库\查询异常] SQLSTATE[HY000]:一般错误:1005 无法创建表 meal.#sql-11d2_1 4 (errno: 150 "外键约束为 格式不正确”)(SQL:alter 表meals添加约束饭菜_category_id_foreign外键(category_id)引用categoriesid)删除 级联)

【问题讨论】:

是否已经创建了类别和用户? 它创建用户,然后是饭菜并收到该错误,然后创建停止,并在删除 (category_id) 后成功完成迁移。 首先请检查您引用的表是否为InnoDB 类型?如果不是,则将其更改为InnoDB,否则外键将不起作用。 【参考方案1】:

@JuanBonnett 的question 启发了我去寻找答案。我使用 Laravel 来自动化这个过程,而不考虑文件本身的创建时间。根据工作流程,“餐食”将在另一个表(类别)之前创建,因为我在类别之前创建了它的模式文件(餐食)。 那是我的错。

【讨论】:

这么傻的东西 :( ,它应该像数据库播种机。我们必须定义订单。【参考方案2】:

在我的情况下,问题是其中一个引用的表是 InnoDB 而另一个是 MyISAM

MyISAM 不支持外键关系。

所以,现在两个表都是InnoDB。问题解决了。

【讨论】:

您是如何更改设置的? 不是设置,是表的属性,这是mysql中转换表的查询:ALTER TABLE table_name ENGINE=InnoDB; 要改变你可以添加: $table->engine = 'InnoDB';到迁移。【参考方案3】:

必须自上而下创建迁移。

首先为不属于任何人的表创建迁移。

然后为属于之前的表创建迁移。


表引擎问题的简化答案:

要为表设置存储引擎,请在架构构建器上设置引擎属性:

Schema::create('users', function ($table) 
    $table->engine = 'InnoDB';

    $table->increments('id');
);

来自 Laravel 文档:https://laravel.com/docs/5.2/migrations

【讨论】:

我们可以控制表格生成的流程(如您所说的自顶向下创建)吗?怎么样? 太棒了!我更改了迁移文件名(时间)并且它起作用了,谢谢:) @himanshubhandari 请注意,一旦您的应用程序投入生产,您不应该以这种方式编辑迁移文件。只需使用所需的 mod 创建一个新的,这样您就不会破坏迁移时间线序列 复制一下,谢谢 :)【参考方案4】:

也许它对任何登陆这里的人都有帮助:我刚刚遇到了同样的问题,在我的情况下,我在外键约束之前在外键列上设置了(复合)唯一约束。我通过将“唯一”语句放在“外国”语句之后解决了这个问题。

作品:

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

【讨论】:

【参考方案5】:

对我来说,一切都井井有条,但仍然无法正常工作。然后我通过摆弄发现主键必须是无符号的。

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

【讨论】:

【参考方案6】:

只需在外键末尾添加->unsigned()->index()即可。

【讨论】:

index() 是多余的,因为默认情况下外键会在该列上生成索引 考虑到您正在尝试添加已在另一个表中声明为无符号的外键,这是一个相关答案。 不得不添加 ->unisigned() 不过对我有用。感谢分享【参考方案7】:

如果您在外键定义中使用 ->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');

【讨论】:

你是个传奇!【参考方案8】:

您应该按顺序创建迁移 例如我希望我的users 有一个来自我的roles 表的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');
    );

【讨论】:

【参考方案9】:

请在您的字段中添加->nullable(),并确保您所指的所有字段都真实存在。

【讨论】:

【参考方案10】:

迁移文件的创建顺序应该是排序的,外键应该和其他表的主键具有完全相同的属性。

【讨论】:

【参考方案11】:

在我的例子中,新的 laravel 约定导致了这个错误。

只需简单地交换表创建 id 就可以了。

$table->increments('id'); // ok

,而不是:

$table->bigIncrements('id'); // was the error.

已经在使用Laravel v5.8,之前从未出现过此错误。

【讨论】:

这个。我怀疑这是我的问题。只需要使该字段可以为空,以及上面的建议。【参考方案12】:

在 Laravel 中创建新表时。将生成如下迁移:

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

你也可以像Kiko Sejio所说的那样使用increments而不是bigIncrements

Integer 和 BigInteger 的区别在于大小:

int => 32 位 bigint => 64 位

【讨论】:

【参考方案13】:

请记住,引用和引用字段必须具有完全相同的数据类型,这一点很重要。

【讨论】:

【参考方案14】:

我收到了相同的数据类型不匹配问题的消息。

我将 bigIncrements() 用于“id”,当我将其用作外键(使用 bigInteger())时出现错误。

我找到了解决方案,bigIncrements() 返回 unsignedBigInteger。所以需要在外键中使用 unsignedBigInteger() 而不是 bigInteger()

分享这个,因为它可能会帮助别人

【讨论】:

这是正确的答案。像魅力一样工作。谢谢【参考方案15】:

创建“餐食”时应先创建类别和用户表

要解决此问题,您应该将类​​别和用户的迁移文件重命名为之前创建膳食表之前的膳食迁移文件的日期。


样本:
2019_04_10_050958_create_users_table 
2019_04_10_051958_create_categories_table
2019_04_10_052958_create_meals_table

【讨论】:

【参考方案16】:

Laravel 5.8

在外键列中使用unsignedBigInteger来避免外键数据类型不匹配的问题。例如,假设我们有两个表 questionsreplies 问题表如下所示:

 public function up()
    
        Schema::create('questions', function (Blueprint $table) 
            $table->bigIncrements('id');
             $table->text('body');
             $table->integer('user_id')->unsigned();
            $table->timestamps();
        );
    

回复表如下所示:

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

【讨论】:

【参考方案17】:

这是一个简单的问题,所以请给出一个简单的答案,不要拐弯抹角, 将您的示例 $table->integer('user_id')->unsigned(); 更改为 $table->BigInteger('user_id')->unsigned(); 以解决外键错误。所以在迁移文件中将整数更改为 BigInteger...

【讨论】:

【参考方案18】:

解决外键错误的一种方法是禁用检查:“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;');

【讨论】:

解释你的答案是做什么的 我的情况:1 个新表 Media 和 1 个具有新列 media_id 的现有表。 media_id 可以为空,默认为空。只有在禁用 FOREIGN_KEY_CHECKS 时才会创建外键。 Laravel 方式:Schema::disableForeignKeyConstraints();Schema::enableForeignKeyConstraints();【参考方案19】:

我只是使用 $table->unsignedBigInteger('user_id'); 并解决它。 (laravel 5.8)

【讨论】:

【参考方案20】:

Laravel 6:2020 年 1 月 17 日更新

$table->bigInteger( 'category_id' )->unsigned();

这对我很有效

【讨论】:

【参考方案21】:
    签入您的数据库引用表必须具有主键 && 自动增量 删除要迁移的表并再次运行迁移

【讨论】:

【参考方案22】:

我不得不在 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');

使用等效的“大整数”递增 ID。

用大整数代替整数

    如果现在仍然出现错误。

我建议您通过以下方式重新排序迁移文件:

更改构成迁移文件名第一部分的日期 所以它们按照您想要的顺序排列(例如:for 2020_07_28_133303_update_categories.php,日期和时间是 2020-07-28, 13:33:03);

注意:首先必须是 'categories' 迁移文件,而不是 'meals' 迁移 文件。

注: 在 Laravel 5.6 中, 对于$table->increments('id'); 使用$table->integer('user_id')->unsigned();

【讨论】:

【参考方案23】:

我刚刚加了

$table->engine = 'MyISAM';

成功了。 这是因为 laravel 默认使用 InnoDB Engine 创建表。

【讨论】:

MyISAM 不支持外键,如何解决?【参考方案24】:

我遇到了同样的问题,所以我更改了迁移的创建日期,更改了这一点,我更改了迁移的执行顺序,所需的表是在我使用它作为外键的表的第一个创建的

p>

【讨论】:

【参考方案25】:

就我而言,问题在于表的引擎之间的差异。在我引用的表中,我没有指定引擎。

没用

// 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();
);

为了控制它,我建议在所有迁移中设置引擎以创建表。 (不要相信默认数据库设置)

有效

// 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();
);

【讨论】:

【参考方案26】:

我正在使用 Laravel 8 并且有同样的错误。问题是这些列(例如 users.id 和饭菜.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) unsinged AUTO ICREMENT。

如果我们转到另一个要设置外键的表,例如下面的我也将 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']);


); 

【讨论】:

【参考方案27】:

您只需要按顺序创建迁移。确保首先创建不接收任何外键的表。然后创建那些做的。 如果您已经创建了迁移,只需更改迁移的时间或日期,以便未接收任何外键的表在收到的表之前创建。

【讨论】:

以上是关于Laravel 迁移:“外键约束格式不正确”(errno 150)的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 迁移:“外键约束格式不正确”(errno 150)

laravel 5.4 迁移错误:150“外键约束格式不正确”

Laravel 迁移错误:150“外键约束格式不正确”

Laravel-7 迁移中的外键约束形成错误

Laravel 迁移不能在用户表中添加外键

Laravel 上的“外键约束格式不正确”