Porzucanie kolumny z kluczem obcym Błąd Laravel: Błąd ogólny: 1025 Błąd podczas zmiany nazwy

96

Utworzyłem tabelę przy użyciu migracji w następujący sposób:

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

Muszę zmienić tę tabelę i usunąć odwołanie do klucza obcego i kolumnę pick_detail_idoraz dodać nową kolumnę varchar o nazwie skupo pick_idkolumnie.

Utworzyłem więc kolejną migrację, która wygląda następująco:

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

Kiedy uruchamiam tę migrację, pojawia się następujący błąd:

[Illuminate \ Database \ QueryException]
SQLSTATE [HY000]: Błąd ogólny: 1025 Błąd podczas zmiany nazwy „./dev_iwms_reboot/despatch_discrepancies” na „./dev_iwms_reboot/#sql2-67c-17c464” (errno: 152) (SQL: alter table despatch_discrepanciesupuść klucz obcy pick_detail_id)

[PDOException]
SQLSTATE [HY000]: Błąd ogólny: 1025 Błąd podczas zmiany nazwy „./dev_iwms_reboot/despatch_discrepancies” na „./dev_iwms_reboot/#sql2-67c-17c464” (errno: 152)

Kiedy próbuję cofnąć tę migrację, uruchamiając php artisan migrate:rollbackpolecenie, otrzymuję Rolled backkomunikat, ale tak naprawdę nic nie robi w bazie danych.

Masz jakiś pomysł, co może być nie tak? Jak usunąć kolumnę zawierającą odniesienie do klucza obcego?

Tokarski
źródło

Odpowiedzi:

172

Możesz użyć tego:

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

Jeśli osiągniesz szczyt w źródle dropForeign, utworzy on dla ciebie nazwę indeksu klucza obcego, jeśli przekażesz nazwę kolumny jako tablicę.

Alex Pineda
źródło
3
Zaakceptowana odpowiedź też działa: musisz użyć właściwej konwencji nazwy indeksu. Ale to też jest problem z tą odpowiedzią: musisz zapamiętać schemat nazewnictwa indeksów, podczas gdy to rozwiązanie robi to automatycznie! Zawsze korzystałem z odwrotnej strony i zawsze narzekałem, że to niepraktyczne. Teraz od razu przechodzę na to rozwiązanie. Dziękuję Ci bardzo!
Marco Pallante,
7
Niesamowita sztuczka. Robiłem to od dawna jak frajer. Laravel naprawdę przydałby się pomoc w dokumentacji. Mogę podjąć wyzwanie ...
simonhamp
1
Pracował dla mnie w Laravel 5.0. Wielkie dzięki, Alex!
SilithCrowe
1
Działał jak urok w Laravel 5.2.
ronin1184
3
To niezła sztuczka. O wiele bardziej przyjazny niż pamiętanie konwencji nazewnictwa kluczy obcych (która może ulec zmianie w przyszłości). Jak powiedział @ ronin1184, działa doskonale w Laravel 5.2
Robin van Baalen
81

Wyszło na to, że; podczas tworzenia klucza obcego w ten sposób:

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

Laravel jednoznacznie nazywa odwołanie do klucza obcego w następujący sposób:

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

Dlatego jeśli chcesz usunąć kolumnę z odniesieniem do klucza obcego, musisz to zrobić w następujący sposób:

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

Aktualizacja:

Laravel 4.2+ wprowadza nową konwencję nazewnictwa:

<table_name>_<column_name>_foreign
Tokarski
źródło
4
Nie działa w Laravel 4.2. <foreign_table_name> nie jest częścią nazwy klucza. Działa tylko z <table_name> _ <column_name> _foreign.
bogate wspomnienie
Użyłem go w laravel 4.2 i nadal robię, działa na mnie.
Latheesan
2
<table_name>_<column_name>_foreignKonwencja wciąż wydaje się działać na 5,1
Yahya uddin
Najwyraźniej po zniesieniu ograniczenia relacji musisz też upuścić kolumnę. Myślę, że dokumentacja powinna to również zawierać, ponieważ można łatwo założyć, że dropForeign usunie również kolumnę. dzięki za udostępnienie. laravel.com/docs/5.0/schema#dropping-columns
Picrasma
Jeśli ktoś się zastanawiał, indeksy, które MySQL automatycznie tworzy dla kluczy obcych, są odrzucane, gdy kolumny są. Nie trzeba ich ręcznie upuszczać za pomocą $table->dropIndex('column_name').
Aleksandar
25

Miałem wiele kluczy obcych w mojej tabeli, a następnie musiałem usuwać ograniczenia klucza obcego jeden po drugim, przekazując nazwę kolumny jako indeks tablicy w metodzie w dół:

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

Korzystanie z poniższej instrukcji nie działa

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

Ponieważ dropForeign nie uważa ich za oddzielne kolumny, które chcemy usunąć. Musimy więc porzucić je jeden po drugim.

Afraz Ahmad
źródło
Dziękuję przyjacielu, dodanie nazwy kolumny w tablicy działa dla mnie.
Pierre
Jeśli ktoś się zastanawiał, indeksy, które MySQL automatycznie tworzy dla kluczy obcych, są odrzucane, gdy kolumny są. Nie trzeba ich ręcznie upuszczać za pomocą $table->dropIndex('column_name').
Aleksandar
9

Kluczem (dla mnie) do rozwiązania tego problemu było upewnienie się, że do polecenia $ table-> dropForeign () została przekazana właściwa nazwa relacji, niekoniecznie nazwa kolumny. Zdajesz nie chce przekazać nazwę kolumny, jak byłoby znacznie bardziej intuicyjne IMHO.

U mnie zadziałało:

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

Tak więc ciąg, który przekazałem do dropForeign (), który działał dla mnie, był w formacie:

[tabela lokalna] _ [pole klucza obcego] _zewnętrzne

Jeśli masz dostęp do narzędzia takiego jak Sequel Pro lub Navicat, ich wizualizacja będzie bardzo pomocna.

DirtyBirdNJ
źródło
To działa dobrze, po prostu okazało się, że jest mniej intuicyjne niż otaczanie stołu w nawiasach, jak sugerował @Alex.
Mark Karavan
6

Coś, co przyszło mi do głowy, to fakt, że nie wiedziałem, gdzie umieścić Schema::tableblokadę.

Później odkryłem, że klucz jest na błędzie 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`)

Więc Schema::tableblok musi iść w down()funkcji lu_benefits_categoriesmigracji i przed Schema::dropIfExistswierszem:

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

Po tym, php artisan migrate:refreshlub php artisan migrate:resetzałatwi sprawę.

Gus
źródło