无法删除索引“***”:外键约束需要它。

9

我已经创建了唯一索引:

 $table->unique(['owner_id', 'promoter_id']);

现在我尝试将其拖放

$table->dropUnique(['owner_id', 'promoter_id']);

一般错误:1553无法删除索引“connections_owner_id_promoter_id_unique”,因为外键约束需要它(SQL:alter table connections drop index connections_owner_id_promoter_id_unique)

此外,我之前尝试过先删除外键

$table->dropForeign('connections_promoter_id_foreign');

但是仍然没有结果。

这是因为外键的名称是 connections_owner_id_promoter_id_unique,正如错误信息所告诉你的那样。 - Douwe de Haan
@DouwedeHaan 但是我该如何删除它(唯一性),我知道错误的原因,但我不知道该如何解决。 - napalias
$table->dropForeign('connections_owner_id_promoter_id_unique'); - Douwe de Haan
@DouwedeHaan,这个也不行,我仍然得到了错误(不同的错误),说这个键不存在。语法错误或访问违规:1091 无法删除“connections_owner_id_promoter_id_unique”;请检查列/键是否存在(SQL:alter table connections drop foreign key connections_owner_id_promoter_id_unique - napalias
你能提供我们想要修改的表及其相关表的所有迁移吗? - Douwe de Haan
7个回答

7

根据错误消息,似乎您在同一次运行中创建了外键和唯一元组,就像这样:

$table->foreignId('owner_id')->constrained('owners');
$table->unique(['owner_id', 'promoter_id']);

来自 mysql 文档:

MySQL 要求外键列必须建立索引;如果你创建了一个带有外键约束但某个列上没有索引的表,那么将会创建一个索引。

现在,由于你已经创建了一个元组索引,因此owner_id已经拥有了索引(因为它是元组中的第一个,注意promoter_id没有索引),所以 MySQL 不需要创建外键索引。然而,如果你现在删除唯一键约束,你将会拥有一个没有索引的外键,这是不允许的,因此会出现错误信息。

没有必要删除外键。只需要在删除唯一索引之前在该字段上添加一个普通索引即可,像这样:

$table->index('owner_id');
$table->dropUnique(['owner_id', 'promoter_id']);

就是这样。由于你已经对它进行了索引,因此不会出现外键错误。


1
谢谢,这解释了很多! - mniess

5

Laravel关于索引的文档中,你可以创建一个带有指定名称的唯一索引:

Laravel将自动生成一个合理的索引名称,但是你可以传递第二个参数来指定自己的名称:

$table->unique('email', 'unique_email');

为了让你不必调试 laravel 是如何构建索引名称的,你可以在添加索引时指定名称,例如:

$table->unique(['owner_id', 'promoter_id'], 'owner_promoter_index');

然后当您放置它时,使用相同的名称:
$table->dropUnique('owner_promoter_index');

谢谢,这似乎应该可以工作,但是我需要将索引添加到旧的迁移中。 - napalias
@napalias 如果旧迁移没有问题,您不必为其执行此操作。对我来说,给索引命名(当出现问题时)可以让我确信正在使用正确的名称,因此如果之后出现其他问题,我可以将索引命名排除在根本原因之外。 - Oluwatobi Samuel Omisakin
如果您使用数组,Laravel 将自动将其解析为正确的索引名称。因此,$table->dropUnique(['owner_id', 'promoter_id']) 将删除正确的键。但这不是 OP 的问题,问题在于索引和外键之间的冲突,请参见我的答案 https://dev59.com/Lq3la4cB1Zd3GeqPMm_2#73730681。 - Adam

2

基于这个删除多列唯一键而不删除外键?的问题,我得到了这个解决方案,它也可以工作:

Schema::table('connections', function ($table){
            $table->index('owner_id');
            $table->dropUnique(['owner_id', 'promoter_id']);
        });

2
在你的示例中。
$table->unique(['owner_id', 'promoter_id']);

数组中的第一列已经有一个外键和相关的索引。 第一选项是先放置一个还没有外键的字段,例如:
$table->unique(["key", 'owner_id', 'promoter_id']);

但这并非总是可能的。 第二种选择 - 你只需要修改down()函数。
例如,你可以像这样创建自己独特的索引。
$table->unique(['owner_id', 'promoter_id']);

owner_id 是现在让您困扰的字段,因为它在数组中排在第一位。因此,down 函数应该像这样:

$table->dropForeign(['owner_id']);
$table->dropUnique(['owner_id', 'promoter_id']);
$table->foreign('owner_id')->references('id')->on('owners');

第三个选项有点棘手,你的“down”函数将如下所示

$table->index('owner_id');
$table->dropUnique(['owner_id', 'promoter_id']);

它能够工作,但我不建议这样做,因为它不能完全回滚。

如果您使用索引名称records_owner_id_foreign开始,然后执行php artisan migrate,然后执行php artisan migrate:rollback,那么您会发现您的索引名称变成了records_owner_id_index。它不再是相同的索引名称。

因此,在不同的数据库中可能会有不同的索引名称,您喜欢吗?我不喜欢。


1
正是我所需要的,写得非常好! - Mike Mellor
1
我认为他从未想过要回滚。设置唯一键并由于业务变更需要在后续迁移中删除它是很正常的。在这种情况下,我认为第三个选项是正确的。 - Adam

0

尝试这种方式:

   Schema::table('table_name', function (Blueprint $table) {
        
        
        //$table->dropIndex('language_title');            
        //$table->dropUnique('language_title');

        // Integrate them
        $table->dropIndex('language_title')->dropUnique('language_title');
    });

-1

无需禁用或删除唯一索引!只需用另一个覆盖唯一索引即可!

Schema::table('users', function (Blueprint $table) {
    $table->unique(['user_id', 'role_id', 'department_id'],
       'user_roles_user_id_role_id_department_id_unique');
});

-1

首先移除约束。

对于SQLServer: 如果您不知道约束名称,请使用sp_helpconstraint TABLE_A,约束名称可能与索引相同。 然后,alter table TABLE_A drop constraint UQ__TABLE_A_XXXXXXXXXX。然后,删除索引。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接