Bỏ cột với khóa ngoại Lỗi Laravel: Lỗi chung: 1025 Lỗi khi đổi tên


93

Tôi đã tạo một bảng bằng cách di chuyển như thế này:

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

Tôi cần thay đổi bảng này và bỏ tham chiếu khóa ngoại & cột pick_detail_idvà thêm một cột varchar mới được gọi là skusau pick_idcột.

Vì vậy, tôi đã tạo một quá trình di chuyển khác, trông giống như sau:

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

Khi chạy quá trình di chuyển này, tôi gặp lỗi sau:

[Illuminate \ Database \ QueryException]
SQLSTATE [HY000]: Lỗi chung: 1025 Lỗi khi đổi tên của './dev_iwms_reboot/despatch_discrepancies' to './dev_iwms_reboot/#sql2-67c-17c464' (errno: 152) (SQL: alter table despatch_discrepanciesthả khóa ngoại pick_detail_id)

[PDOException]
SQLSTATE [HY000]: Lỗi chung: 1025 Lỗi khi đổi tên của './dev_iwms_reboot/despatch_discrepancies' thành './dev_iwms_reboot/#sql2-67c-17c464' (errno: 152)

Khi tôi cố gắng đảo ngược quá trình di chuyển này bằng cách chạy php artisan migrate:rollbacklệnh, tôi nhận được một Rolled backthông báo, nhưng nó không thực sự làm bất cứ điều gì trong cơ sở dữ liệu.

Bất cứ ý tưởng những gì có thể là sai? Làm thế nào để bạn bỏ một cột có tham chiếu khóa ngoại?

Câu trả lời:


166

Bạn có thể sử dụng cái này:

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

Nếu bạn lấy đỉnh tại nguồn dropForeign, nó sẽ xây dựng tên chỉ mục khóa ngoại cho bạn nếu bạn chuyển tên cột dưới dạng một mảng.


2
Câu trả lời được chấp nhận cũng hoạt động: bạn phải sử dụng quy ước tên chỉ mục phù hợp. Nhưng đây cũng là vấn đề với câu trả lời đó: bạn phải nhớ sơ đồ đặt tên cho các chỉ mục, trong khi giải pháp này tự động làm điều đó! Tôi luôn sử dụng cách khác, và luôn phàn nàn về cách nó không thực tế. Bây giờ tôi ngay lập tức chuyển sang giải pháp này. Cảm ơn rât nhiều!
Marco Pallante

6
Thủ thuật tuyệt vời. Tôi đã làm điều đó suốt một chặng đường dài như một kẻ hút máu. Laravel thực sự có thể sử dụng một số trợ giúp về tài liệu. Tôi có thể mất đến thách thức ...
simonhamp

1
Làm việc cho tôi trong Laravel 5.0. Cảm ơn rất nhiều, Alex!
SilithCrowe

1
Hoạt động như một sự quyến rũ trong Laravel 5.2.
ronin1184

3
Đây là một mẹo nhỏ. Thân thiện hơn là nhớ quy ước đặt tên khóa ngoại (có thể thay đổi trong tương lai). Giống như @ ronin1184 nói, hoạt động hoàn hảo trong Laravel 5.2
Robin van Baalen

81

Hóa ra; khi bạn tạo một khóa ngoại như sau:

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

Laravel đặt tên duy nhất cho tham chiếu khóa ngoại như sau:

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

Do đó, khi bạn muốn bỏ một cột có tham chiếu khóa ngoại, bạn phải làm như sau:

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

Cập nhật:

Laravel 4.2+ giới thiệu một quy ước đặt tên mới:

<table_name>_<column_name>_foreign

4
Không hoạt động trong Laravel 4.2. <foreign_table_name> không phải là một phần của tên khóa. Nó chỉ hoạt động với <tên_bảng> _ <tên_tên_cấp> _đặt.
rich remer

Tôi đã sử dụng nó trong laravel 4.2 và vẫn làm, nó hoạt động với tôi.
Latheesan

2
Quy <table_name>_<column_name>_foreignước dường như vẫn hoạt động cho 5.1
Yahya Uddin

Rõ ràng, sau khi bỏ ràng buộc về mối quan hệ, bạn cũng phải bỏ cột. tôi nghĩ rằng tài liệu cũng nên bao gồm điều đó vì người ta có thể dễ dàng cho rằng dropForeign cũng sẽ xóa cột. cảm ơn vì sự chia sẻ. laravel.com/docs/5.0/schema#dropping-columns
Picrasma

Nếu có ai đó đang thắc mắc, các chỉ mục mà MySQL tự động tạo cho các khóa ngoại sẽ bị loại bỏ khi các cột bị loại bỏ. Không cần phải thả chúng theo cách thủ công với $table->dropIndex('column_name').
Aleksandar

24

Tôi có nhiều khóa ngoại trong bảng của mình và sau đó tôi phải xóa từng ràng buộc khóa ngoại một bằng cách chuyển tên cột làm chỉ số của mảng trong phương thức 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']);
    });
} 

Sử dụng câu lệnh dưới đây không hoạt động

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

Bởi vì dropForeign không coi chúng là các cột riêng biệt mà chúng ta muốn loại bỏ. Vì vậy, chúng tôi phải thả từng cái một.


Cảm ơn bạn của tôi, thêm tên cột trong một mảng phù hợp với tôi.
Pierre

Nếu có ai đó đang thắc mắc, các chỉ mục mà MySQL tự động tạo cho các khóa ngoại sẽ bị loại bỏ khi các cột bị loại bỏ. Không cần phải thả chúng theo cách thủ công với $table->dropIndex('column_name').
Aleksandar

9

Chìa khóa (đối với tôi) để giải quyết vấn đề này là đảm bảo rằng lệnh $ table-> dropForeign () đang được chuyển đúng tên quan hệ, không nhất thiết phải là tên cột. Bạn không muốn chuyển tên cột, vì IMHO sẽ trực quan hơn nhiều.

Điều làm việc cho tôi là:

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

Vì vậy, chuỗi tôi đã chuyển đến dropForeign () hoạt động với tôi có định dạng:

[bảng cục bộ] _ [trường khóa ngoại] _foreign

Nếu bạn có quyền truy cập vào một công cụ như Sequel Pro hoặc Navicat, có thể hình dung chúng sẽ rất hữu ích.


Điều này hoạt động tốt, tôi chỉ thấy nó kém trực quan hơn so với việc đặt bảng trong ngoặc như @Alex đề xuất.
Mark Karavan

5

Một điều gì đó xảy ra với tôi là tôi không biết phải đặt Schema::tablekhối ở đâu.

Sau đó, tôi phát hiện ra rằng khóa nằm trên lỗi 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`)

Vì vậy, Schema::tablekhối cần phải thực hiện down()chức năng của việc lu_benefits_categoriesdi chuyển và trước Schema::dropIfExistsdòng:

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

Sau đó, php artisan migrate:refreshhoặc php artisan migrate:resetsẽ thực hiện thủ thuật.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.