Laravel migration 删除外键并新增字段时出现 1091 错误怎么办?
该错误表示数据库中找不到名为 pallet_distributions_rental_purchase_order_id_foreign 的外键约束。先查询表中实际存在的约束,再将 dropForeign() 改为使用实际名称。
现有代码的 down() 使用了自定义名称 rental_purchase_order_fk_10721477,但仅凭这段代码,无法确认当前数据库中的旧外键是否使用该名称,需要查询核实。
为什么 Laravel 会删除这个名称的外键?
这段写法向 dropForeign() 传入了列名数组:
$table->dropForeign(['rental_purchase_order_id']);
Laravel 会根据表名和列名,按默认命名规则推导出外键名称:
pallet_distributions_rental_purchase_order_id_foreign
如果创建外键时指定了自定义名称,删除时就需要传入对应的约束名称。即使字段存在,也不代表这个默认名称的外键存在。
先确认数据库中的实际约束
在 migration 使用的同一个数据库连接中执行:
SHOW CREATE TABLE `pallet_distributions`;
检查结果中的 CONSTRAINT ... FOREIGN KEY 定义,找到关联 rental_purchase_order_id 的那一条。使用 CONSTRAINT 后面的名称;普通 KEY 的索引名称不能代替外键约束名称。
如果没有找到该字段对应的外键,就不要执行这条 dropForeign()。还要检查旧字段是否存在,以确定后续能否执行 dropColumn()。
使用核实后的名称修改 migration
如果查询确认旧外键名称是 rental_purchase_order_fk_10721477,可以将 up() 改为:
public function up()
{
Schema::table('pallet_distributions', function (Blueprint $table) {
$table->dropForeign('rental_purchase_order_fk_10721477');
});
Schema::table('pallet_distributions', function (Blueprint $table) {
$table->dropColumn('rental_purchase_order_id');
$table->unsignedBigInteger('origin_rental_purchase_order_id')
->nullable();
$table->unsignedBigInteger('destination_rental_purchase_order_id')
->nullable();
});
Schema::table('pallet_distributions', function (Blueprint $table) {
$table->foreign(
'origin_rental_purchase_order_id',
'origin_rental_purchase_order_fk_10726539'
)
->references('id')
->on('rental_purchase_orders');
$table->foreign(
'destination_rental_purchase_order_id',
'destination_rental_purchase_order_fk_10746540'
)
->references('id')
->on('rental_purchase_orders');
});
}
如果查到的是其他名称,应替换示例中的旧外键名称。这里拆成几个 Schema::table() 调用,是为了明确操作顺序:先删除约束,再调整字段,最后创建新约束。解决本次 1091 错误仍需使用正确的约束名称。
原有 down() 已按自定义名称删除两个新外键;重新创建旧外键时使用的名称,也应与计划恢复的表结构保持一致。
删除字段前处理数据和执行状态
dropColumn('rental_purchase_order_id') 会删除旧字段中的数据。如果需要保留关联关系,应先新增两个字段,按业务规则复制数据,核对结果后再删除旧字段。现有信息不足以判断旧值应写入 origin、destination,还是两个字段都写入,因此不能直接给出复制规则。
还要确认以下事项:
rental_purchase_orders.id的类型与新字段兼容,尤其是整数大小和 unsigned 属性。- migration 失败后,先检查当前表结构。MySQL 的 DDL 操作可能留下部分已完成的变更,不能假设所有操作都已回滚。
down()只能按代码重建字段和约束,无法自动恢复已删除的数据。还应根据真实表结构核对旧字段原有的类型、可空性等属性。
备注:内容仅供参考。
