删除带有外键Laravel的列错误:常规错误:1025重命名错误


93

我已经使用迁移创建了一个表,如下所示:

public function up()
{
    Schema::create('despatch_discrepancies',  function($table) {
        $table->increments('id')->unsigned();
        $table->integer('pick_id')->unsigned();
        $table->foreign('pick_id')->references('id')->on('picks');
        $table->integer('pick_detail_id')->unsigned();
        $table->foreign('pick_detail_id')->references('id')->on('pick_details');
        $table->integer('original_qty')->unsigned();
        $table->integer('shipped_qty')->unsigned();
    });
}

public function down()
{
    Schema::drop('despatch_discrepancies');
}

我需要更改此表并删除外键引用和列,pick_detail_id并添加一个新的varchar列,此列称为skuafter pick_idcolumn。

因此,我创建了另一个迁移,如下所示:

public function up()
{
    Schema::table('despatch_discrepancies', function($table)
    {
        $table->dropForeign('pick_detail_id');
        $table->dropColumn('pick_detail_id');
        $table->string('sku', 20)->after('pick_id');
    });
}

public function down()
{
    Schema::table('despatch_discrepancies', function($table)
    {
        $table->integer('pick_detail_id')->unsigned();
        $table->foreign('pick_detail_id')->references('id')->on('pick_details');
        $table->dropColumn('sku');
    });
}

运行此迁移时,出现以下错误:

[Illuminate \ Database \ QueryException]
SQLSTATE [HY000]:常规错误:1025将“ ./dev_iwms_reboot/despatch_discrepancies”重命名为“ ./dev_iwms_reboot/#sql2-67c-17c464”(错误:152)(SQL:更改表)时出错 despatch_discrepancies删除外键pick_detail_id)

[PDOException]
SQLSTATE [HY000]:常规错误:1025将“ ./dev_iwms_reboot/despatch_discrepancies”重命名为“ ./dev_iwms_reboot/#sql2-67c-17c464”时出错(错误:152)

当我尝试通过运行php artisan migrate:rollback命令来逆转这种迁移时,我收到一条Rolled back消息,但实际上并没有在数据库中做任何事情。

知道有什么问题吗?如何删除具有外键引用的列?

Answers:


166

您可以使用此:

$table->dropForeign(['pick_detail_id']);
$table->dropColumn('pick_detail_id');

如果您在dropForeign源代码中达到顶峰,则当您将列名作为数组传递时,它将为您构建外键索引名。


2
可接受的答案也适用:您必须使用正确的索引名称约定。但这也是答案的问题:您必须记住索引的命名方案,而此解决方案会自动执行!我总是用另一种方式,并且总是抱怨那是不切实际的。现在,我立即切换到此解决方案。非常感谢你!
Marco Pallante 2015年

6
很棒的把戏。我已经像吸盘一样长途跋涉。Laravel确实可以在文档上使用一些帮助。我可能会接受挑战...
simonhamp 2015年

1
在Laravel 5.0中为我工作。非常感谢,Alex!
SilithCrowe '16

1
在Laravel 5.2中像灵符一样工作。
ronin1184 '16

3
这是一个巧妙的把戏。比记住外键命名约定(将来可能会更改)更友好。就像@ ronin1184所说的那样,可以在Laravel 5.2中完美运行
Robin van Baalen

81

原来;当您创建这样的外键时:

$table->integer('pick_detail_id')->unsigned();
$table->foreign('pick_detail_id')->references('id')->on('pick_details');

Laravel像这样唯一地命名外键引用:

<table_name>_<foreign_table_name>_<column_name>_foreign
despatch_discrepancies_pick_detail_id_foreign (in my case)

因此,当您要删除带有外键引用的列时,您必须这样做:

$table->dropForeign('despatch_discrepancies_pick_detail_id_foreign');
$table->dropColumn('pick_detail_id');

更新:

Laravel 4.2+引入了新的命名约定:

<table_name>_<column_name>_foreign

4
在Laravel 4.2中不起作用。<foreign_table_name>不是键名的一部分。它仅适用于<table_name> _ <column_name> _foreign。
rich remer

我在laravel 4.2中使用了它,现在仍然可以使用,它对我有用。
Latheesan 2015年

2
<table_name>_<column_name>_foreign公约似乎仍然工作5.1
叶海亚·乌丁

显然,在删除关系约束之后,您也必须删除该列。我认为文档也应该包含该内容,因为可以轻松地假设dropForeign也将删除该列。感谢您的分享。laravel.com/docs/5.0/schema#dropping-columns
Picrasma

如果有人想知道的话,当列为空时,MySQL自动为外键创建的索引将被删除。无需使用手动将其删除$table->dropIndex('column_name')
Aleksandar

24

我的表中有多个外键,然后必须通过在down方法中将列名作为数组的索引传递来逐个删除外键约束:

public function up()
{
    Schema::table('offices', function (Blueprint $table) {
        $table->unsignedInteger('country_id')->nullable();
        $table->foreign('country_id')
            ->references('id')
            ->on('countries')
            ->onDelete('cascade');

        $table->unsignedInteger('stateprovince_id')->nullable();
        $table->foreign('stateprovince_id')
            ->references('id')
            ->on('stateprovince')
            ->onDelete('cascade');
        $table->unsignedInteger('city_id')->nullable();
        $table->foreign('city_id')
            ->references('id')
            ->on('cities')
            ->onDelete('cascade');
    });
}

/**
 * Reverse the migrations.
 *
 * @return void
 */
public function down()
{
    Schema::table('offices', function (Blueprint $table) {
        $table->dropForeign(['country_id']);
        $table->dropForeign(['stateprovince_id']);
        $table->dropForeign(['city_id']);
        $table->dropColumn(['country_id','stateprovince_id','city_id']);
    });
} 

使用以下语句不起作用

$table->dropForeign(['country_id','stateprovince_id','city_id']); 

因为dropForeign不会将它们视为我们要删除的单独的列。因此,我们必须将它们一一删除。


谢谢我的朋友,将列名添加到数组中对我有用。
Pierre

如果有人想知道的话,当列为空时,MySQL自动为外键创建的索引将被删除。无需使用手动删除它们$table->dropIndex('column_name')
Aleksandar

9

(对我而言)解决此问题的关键是确保向$ table-> dropForeign()命令传递了正确的关系名称,而不必传递列名称。您希望传递列名,就像更直观的恕我直言。

对我有用的是:

$table->dropForeign('local_table_foreign_id_foreign');
$table->column('foreign_id');

因此,我传递给dropForeign()的对我有用的字符串的格式为:

[本地表] _ [外键字段] _foreign

如果您可以使用Sequel Pro或Navicat之类的工具,那么对这些工具进行可视化将非常有帮助。


效果很好,我只是发现它不如@Alex建议的那样将表格放在方括号内。
马克·卡拉万

5

我发生的事情是我不知道将障碍物放在哪里Schema::table

后来我发现键在SQL错误上:

[Illuminate\Database\QueryException]
SQLSTATE[23000]: Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails (SQL: drop table if exists `lu_benefits_categories`)

因此,该Schema::table块需要进入迁移down()功能lu_benefits_categories并在该Schema::dropIfExists行之前:

public function down()
{
    Schema::table('table', function (Blueprint $table) {
        $table->dropForeign('table_category_id_foreign');
        $table->dropColumn('category_id');
    });
    Schema::dropIfExists('lu_benefits_categories');
}

之后,php artisan migrate:refreshphp artisan migrate:reset会成功。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.