Dejar caer la columna con clave externa error de Laravel: error general: error 1025 al cambiar el nombre


94

Creé una tabla usando una migración como esta:

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

Necesito cambiar esta tabla y eliminar la referencia y columna de clave externa pick_detail_idy agregar una nueva columna varchar llamada skudespués de la pick_idcolumna.

Entonces, he creado otra migración, que se ve así:

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

Cuando ejecuto esta migración, aparece el siguiente error:

[Illuminate \ Database \ QueryException]
SQLSTATE [HY000]: Error general: 1025 Error al cambiar el nombre de './dev_iwms_reboot/despatch_discrepancies' a './dev_iwms_reboot/#sql2-67c-17c464' (errno: 152) (SQL: alter table despatch_discrepanciessoltar clave externa pick_detail_id)

[PDOException]
SQLSTATE [HY000]: Error general: 1025 Error al cambiar el nombre de './dev_iwms_reboot/despatch_discrepancies' a './dev_iwms_reboot/#sql2-67c-17c464' (errno: 152)

Cuando intento revertir esta migración ejecutando el php artisan migrate:rollbackcomando, aparece un Rolled backmensaje, pero en realidad no está haciendo nada en la base de datos.

¿Alguna idea de lo que podría estar mal? ¿Cómo se suelta una columna que tiene una referencia de clave externa?

Respuestas:


167

Puedes usar esto:

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

Si toma un pico en la fuente dropForeign, creará el nombre del índice de clave externa para usted si pasa el nombre de la columna como una matriz.


2
La respuesta aceptada también funciona: debe usar la convención de nombre de índice correcta. Pero este es el problema con esa respuesta también: debe recordar el esquema de nombres para los índices, ¡mientras que esta solución lo hace automáticamente! Siempre lo usaba al revés y siempre me quejaba de lo poco práctico que era. Ahora estoy cambiando inmediatamente a esta solución. ¡Muchas gracias!
Marco Pallante

6
Truco impresionante. Lo he estado haciendo a lo largo del camino como un tonto. Laravel realmente necesitaría ayuda con los documentos. Puedo aceptar el desafío ...
simonhamp

1
Trabajó para mí en Laravel 5.0. ¡Muchas gracias, Alex!
SilithCrowe

1
Funcionó como un encanto en Laravel 5.2.
ronin1184

3
Este es un buen truco. Mucho más amigable que recordar la convención de nomenclatura de claves externas (que podría cambiar en el futuro). Como dijo @ ronin1184, funciona perfectamente en Laravel 5.2
Robin van Baalen

81

Resulta; cuando crea una clave externa como esta:

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

Laravel nombra de forma única la referencia de clave externa así:

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

Por lo tanto, cuando desee eliminar una columna con referencia de clave externa, debe hacerlo así:

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

Actualizar:

Laravel 4.2+ introduce una nueva convención de nomenclatura:

<table_name>_<column_name>_foreign

4
No funciona en Laravel 4.2. <nombre_tabla_extranjero> no forma parte del nombre de la clave. Funciona solo con <table_name> _ <column_name> _foreign.
rich remer

Lo usé en laravel 4.2 y todavía lo hago, funciona para mí.
Latheesan

2
La <table_name>_<column_name>_foreignconvención todavía parece funcionar para 5.1
Yahya Uddin

Aparentemente, después de eliminar la restricción de la relación, también debe eliminar la columna. Creo que la documentación debería haber incluido eso también porque uno puede asumir fácilmente que dropForeign también eliminará la columna. gracias por compartir. laravel.com/docs/5.0/schema#dropping-columns
Picrasma

Si alguien se pregunta, los índices que MySQL crea automáticamente para claves externas se eliminan cuando las columnas lo son. No es necesario soltarlos manualmente con $table->dropIndex('column_name').
Aleksandar

24

Tenía varias claves externas en mi tabla y luego tuve que eliminar las restricciones de clave externa una por una pasando el nombre de la columna como índice de la matriz en el método 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']);
    });
} 

El uso de la siguiente declaración no funciona

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

Porque dropForeign no las considera columnas separadas que queremos eliminar. Entonces tenemos que dejarlos caer uno por uno.


Gracias amigo, agregar el nombre de la columna en una matriz me funciona.
Pierre

Si alguien se pregunta, los índices que MySQL crea automáticamente para claves externas se eliminan cuando las columnas lo hacen. No es necesario soltarlos manualmente con $table->dropIndex('column_name').
Aleksandar

9

La clave (para mí) para resolver esto fue asegurarse de que el comando $ table-> dropForeign () recibiera el nombre de relación correcto, no necesariamente el nombre de la columna. Usted no desea pasar el nombre de la columna, como sería mi humilde opinión mucho más intuitivo.

Lo que funcionó para mí fue:

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

Entonces, la cadena que pasé a dropForeign () que funcionó para mí estaba en el formato de:

[tabla local] _ [campo de clave externa] _extranjero

Si tiene acceso a una herramienta como Sequel Pro o Navicat, será muy útil poder visualizarlas.


Esto funciona bien, me pareció menos intuitivo que rodear la tabla entre corchetes como sugirió @Alex.
Mark Karavan

5

Algo que se me ocurrió fue que no sabía dónde poner el Schema::table bloque.

Más tarde descubrí que la clave está en el error 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`)

Entonces el Schema::tablebloque debe ir en down()función de la lu_benefits_categoriesmigración y antes de la Schema::dropIfExistslínea:

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

Después de eso, el php artisan migrate:refresho php artisan migrate:resethará el truco.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.