Suppression de la colonne avec une clé étrangère Erreur Laravel: Erreur générale: 1025 Erreur lors du changement de nom

94

J'ai créé une table en utilisant la migration comme celle-ci:

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

Je dois changer cette table et supprimer la référence et la colonne de clé étrangère pick_detail_idet ajouter une nouvelle colonne varchar appelée skuaprès la pick_idcolonne.

Donc, j'ai créé une autre migration, qui ressemble à ceci:

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

Lorsque j'exécute cette migration, j'obtiens l'erreur suivante:

[Illuminate \ Database \ QueryException]
SQLSTATE [HY000]: Erreur générale: 1025 Erreur lors du changement de nom de './dev_iwms_reboot/despatch_discrepancies' en './dev_iwms_reboot/#sql2-67c-17c464' (numéro d'erreur: 152) (SQL: modifier la table despatch_discrepanciesdéposer la clé étrangère pick_detail_id)

[PDOException]
SQLSTATE [HY000]: Erreur générale: 1025 Erreur lors du changement de nom de «./dev_iwms_reboot/despatch_discrepancies» en «./dev_iwms_reboot/#sql2-67c-17c464» (numéro d'erreur: 152)

Lorsque j'essaye d'inverser cette migration en exécutant la php artisan migrate:rollbackcommande, j'obtiens un Rolled backmessage, mais cela ne fait rien dans la base de données.

Une idée de ce qui ne va pas? Comment supprimer une colonne qui a une référence de clé étrangère?

Latheesan
la source

Réponses:

167

Vous pouvez utiliser ceci:

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

Si vous prenez un pic à la source dropForeign, il construira le nom de l'index de clé étrangère pour vous si vous passez le nom de la colonne sous forme de tableau.

Alex Pineda
la source
2
La réponse acceptée fonctionne aussi: vous devez utiliser la bonne convention de nom d'index. Mais c'est aussi le problème avec cette réponse: vous devez vous souvenir du schéma de dénomination des index, alors que cette solution le fait automatiquement! J'ai toujours utilisé l'autre manière, et je me suis toujours plaint de son manque de réalisme. Maintenant, je passe immédiatement à cette solution. Merci beaucoup!
Marco Pallante
6
Super truc. Je le fais depuis longtemps comme une ventouse. Laravel pourrait vraiment utiliser de l'aide sur la documentation. Je peux relever le défi ...
simonhamp
1
A travaillé pour moi dans Laravel 5.0. Merci beaucoup, Alex!
SilithCrowe
1
A fonctionné comme un charme dans Laravel 5.2.
ronin1184
3
C'est un truc sympa. Bien plus convivial que de se souvenir de la convention de dénomination des clés étrangères (qui pourrait changer à l'avenir). Comme @ ronin1184 l'a dit, fonctionne parfaitement dans Laravel 5.2
Robin van Baalen
81

Il s'avère; lorsque vous créez une clé étrangère comme celle-ci:

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

Laravel nomme de manière unique la référence de clé étrangère comme suit:

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

Par conséquent, lorsque vous souhaitez supprimer une colonne avec une référence de clé étrangère, vous devez le faire comme suit:

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

Mise à jour:

Laravel 4.2+ introduit une nouvelle convention de dénomination:

<table_name>_<column_name>_foreign
Latheesan
la source
4
Ne fonctionne pas dans Laravel 4.2. <nom_table_étranger> ne fait pas partie du nom de la clé. Cela fonctionne uniquement avec <table_name> _ <column_name> _foreign.
riche remer
Je l'ai utilisé dans laravel 4.2 et je le fais toujours, cela fonctionne pour moi.
Latheesan
2
La <table_name>_<column_name>_foreignconvention semble toujours fonctionner pour 5.1
Yahya Uddin
Apparemment, après avoir supprimé la contrainte sur la relation, vous devez également supprimer la colonne. Je pense que la documentation aurait dû inclure cela aussi car on peut facilement supposer que dropForeign supprimera également la colonne. merci pour le partage. laravel.com/docs/5.0/schema#dropping-columns
Picrasma
Si quelqu'un se posait la question, les index que MySQL crée automatiquement pour les clés étrangères sont supprimés lorsque les colonnes le sont. Pas besoin de les déposer manuellement avec $table->dropIndex('column_name').
Aleksandar
24

J'avais plusieurs clés étrangères dans ma table, puis j'ai dû supprimer les contraintes de clé étrangère une par une en passant le nom de la colonne comme index du tableau dans la méthode 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']);
    });
} 

L'utilisation de l'instruction ci-dessous ne fonctionne pas

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

Parce que dropForeign ne les considère pas comme des colonnes séparées que nous voulons supprimer. Nous devons donc les supprimer un par un.

Afraz Ahmad
la source
Merci mon ami, ajouter le nom de la colonne dans un tableau fonctionne pour moi.
Pierre
Si quelqu'un se posait la question, les index que MySQL crée automatiquement pour les clés étrangères sont supprimés lorsque les colonnes le sont. Pas besoin de les déposer manuellement avec $table->dropIndex('column_name').
Aleksandar
9

La clé (pour moi) pour résoudre ce problème était de s'assurer que la commande $ table-> dropForeign () recevait le bon nom de relation, pas nécessairement le nom de la colonne. Vous ne pas voulez passer le nom de colonne, comme ce serait à mon humble avis beaucoup plus intuitive.

Ce qui a fonctionné pour moi était:

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

Donc, la chaîne que j'ai passée à dropForeign () qui fonctionnait pour moi était au format:

[table locale] _ [champ de clé étrangère] _foreign

Si vous avez accès à un outil comme Sequel Pro ou Navicat, il sera très utile de pouvoir les visualiser.

DirtyBirdNJ
la source
Cela fonctionne bien, j'ai juste trouvé que c'était moins intuitif que d'entourer le tableau entre crochets comme @Alex l'a suggéré.
Mark Karavan
5

Quelque chose qui m'est venu à l'esprit était que je ne savais pas où placer le Schema::tablebloc.

Plus tard, j'ai découvert que la clé est sur l'erreur 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`)

Le Schema::tablebloc doit donc aller dans la down()fonction de la lu_benefits_categoriesmigration et avant la Schema::dropIfExistsligne:

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

Après cela, le php artisan migrate:refreshou php artisan migrate:resetfera l'affaire.

Gus
la source