Laravel Migration Change to Make a Column Nullable

194

Utworzyłem migrację z niepodpisanym user_id. Jak mogę edytować user_idnową migrację, aby to zrobić nullable()?

Schema::create('throttle', function(Blueprint $table)
{
    $table->increments('id');
    // this needs to also be nullable, how should the next migration be?
    $table->integer('user_id')->unsigned();
}
użytkownik391986
źródło

Odpowiedzi:

263

Laravel 5 obsługuje teraz zmianę kolumny; oto przykład z oficjalnej dokumentacji:

Schema::table('users', function($table)
{
    $table->string('name', 50)->nullable()->change();
});

Źródło: http://laravel.com/docs/5.0/schema#changing-columns

Laravel 4 nie obsługuje modyfikowania kolumn, więc musisz użyć innej techniki, takiej jak napisanie surowego polecenia SQL. Na przykład:

// getting Laravel App Instance
$app = app();

// getting laravel main version
$laravelVer = explode('.',$app::VERSION);

switch ($laravelVer[0]) {

    // Laravel 4
    case('4'):

        DB::statement('ALTER TABLE `pro_categories_langs` MODIFY `name` VARCHAR(100) NULL;');
        break;

    // Laravel 5, or Laravel 6
    default:                

        Schema::table('pro_categories_langs', function(Blueprint $t) {
            $t->string('name', 100)->nullable()->change();
        });               

}
MURATSPLAT
źródło
3
Dzięki za to. Ale jak mogę zrobić coś przeciwnego? Jak zmienić kolumnę, aby nie była zerowalna? Jakieś pomysły?
algorhythm
@algorhythm Czy próbujesz tego „$ t-> string („ name ”, 100) -> change (); '
MURATSPLAT
7
Musisz migrować doktrynę \ dbal
ty
33
@algorhythm ->nullable(false)pozwoli ci ponownie zmienić kolumnę.
Colin
9
-> change () wymaga zainstalowania pakietu Doctrine DBAL i nie rozpoznaje z natury wszystkich tych samych typów kolumn, które są dostępne po wyjęciu z pudełka z laravel .. na przykład double nie jest rozpoznawanym typem kolumny dla DBAL.
Will Vincent,
174

Oto pełna odpowiedź dla przyszłego czytelnika. Pamiętaj, że jest to możliwe tylko w Laravel 5+.

Przede wszystkim potrzebujesz pakietu doktryna / dbal :

composer require doctrine/dbal

Teraz podczas migracji możesz to zrobić, aby kolumna miała wartość null:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

Być może zastanawiasz się, jak przywrócić tę operację. Niestety ta składnia nie jest obsługiwana:

// Sadly does not work :'(
$table->integer('user_id')->unsigned()->change();

To jest poprawna składnia do przywrócenia migracji:

$table->integer('user_id')->unsigned()->nullable(false)->change();

Lub, jeśli wolisz, możesz napisać surowe zapytanie:

public function down()
{
    /* Make user_id un-nullable */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

Mam nadzieję, że ta odpowiedź okaże się przydatna. :)

Dmitri Czebotariew
źródło
4
Jest to najbardziej kompletna odpowiedź dla L5, ale należy wspomnieć, że jeśli „identyfikator_użytkownika” jest kluczem obcym, którym powinien być, nie będzie można go zmienić, dopóki nie uruchomisz instrukcji „DB ::” („SET FOREIGN_KEY_CHECKS” = 0 ');' pierwszy. Po zakończeniu ustaw ponownie na 1.
rzb
1
Dziękuję, nullable(false)uratowałeś mnie przed wyciąganiem włosów, ponieważ nullable()nie jest to dobrze udokumentowane i nie ma żadnej notNull()funkcji.
Zack Morris
nie działa to dla kluczy obcych z postgres. próba SET FOREIGN_KEY_CHECKS = 0powoduje błąd. prawdopodobnie będziesz musiał zmienić ograniczenia tabeli przy użyciu surowego zapytania. patrz tutaj: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz
To łamie moje testy. Testy zaczynają się uruchamiać, a następnie zawieszają. Przypuszczam, że powoduje to pierwsze wycofanie. Powoduje zawieszanie testów dla MySQL, a także dla SQLite.
Thomas Praxl
155

Zakładam, że próbujesz edytować kolumnę, do której już dodałeś dane, więc usunięcie kolumny i ponowne dodanie jako kolumny zerowalnej nie jest możliwe bez utraty danych. Będziemy alteristniejącą kolumną.

Jednak konstruktor schematów Laravela nie obsługuje modyfikowania kolumn innych niż zmiana nazwy kolumny. Aby to zrobić, musisz uruchomić nieprzetworzone zapytania:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

Aby mieć pewność, że nadal możesz cofnąć migrację, my również to zrobimy down().

function down()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}

Jedna uwaga jest taka, że ​​ponieważ konwertujesz między wartościami zerowalnymi i zerowymi, musisz upewnić się, że wyczyściłeś dane przed / po migracji. Zrób to w skrypcie migracji na dwa sposoby:

function up()
{
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
    DB::statement('UPDATE `throttle` SET `user_id` = NULL WHERE `user_id` = 0;');
}

function down()
{
    DB::statement('UPDATE `throttle` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    DB::statement('ALTER TABLE `throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Unnawut
źródło
7
Dla laravel 4, zastąpić queryprzezstatement
Razor
2
Dzięki @Razor. Zaktualizowałem odpowiednio moją odpowiedź.
Unnawut
1
W downfunkcji w drugim bloku kodu instrukcja SQL powinna kończyć się NOT NULL. ( downFunkcja w trzecim przykładzie jest poprawna).
Scott Weldon
46

To pełna migracja dla Laravela 5 :

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable()->change();
    });
}

public function down()
{
    Schema::table('users', function (Blueprint $table) {
        $table->unsignedInteger('user_id')->nullable(false)->change();
    });
}

Chodzi o to, że możesz usunąć nullableprzekazując falsejako argument.

Yauheni Prakopchyk
źródło
16

Jeśli zdarzy ci się zmienić kolumny i potknął się

'Doctrine\DBAL\Driver\PDOMySql\Driver' not found

następnie po prostu zainstaluj

composer require doctrine/dbal

rozpoznać
źródło
1
To mnie ugryzło, więc posunąłem
Beau Simensen
9

Dodanie do odpowiedzi Dmitrija Chebotareva, podobnie jak w przypadku Laravela 5+.

Po wymaganiu pakietu doktryna / dbal :

composer require doctrine/dbal

Następnie możesz wykonać migrację z zerowymi kolumnami, na przykład:

public function up()
{
    Schema::table('users', function (Blueprint $table) {
        // change() tells the Schema builder that we are altering a table
        $table->integer('user_id')->unsigned()->nullable()->change();
    });
}

Aby cofnąć operację, wykonaj:

public function down()
{
    /* turn off foreign key checks for a moment */
    DB::statement('SET FOREIGN_KEY_CHECKS = 0');
    /* set null values to 0 first */
    DB::statement('UPDATE `users` SET `user_id` = 0 WHERE `user_id` IS NULL;');
    /* alter table */
    DB::statement('ALTER TABLE `users` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
    /* finally turn foreign key checks back on */
    DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}
rzb
źródło
3

Dodanie do odpowiedzi Dmitrija Chebotareva,

Jeśli chcesz zmienić wiele kolumn jednocześnie, możesz to zrobić jak poniżej

DB::statement('
     ALTER TABLE `events` 
            MODIFY `event_date` DATE NOT NULL,
            MODIFY `event_start_time` TIME NOT NULL,
            MODIFY `event_end_time` TIME NOT NULL;
');
Sameer
źródło
2

Spróbuj:

$table->integer('user_id')->unsigned()->nullable();
Adil
źródło
1
Nie zmienia istniejącej kolumny
dVaffection
9
zapomniałeś ->changena końcu i wspomnieć o tym tylko Laravel 5+
Alexander Malakhov
Musisz wymagaćcomposer require doctrine/dbal
Lizesh Shakya
2

Dla Laravela 4.2 powyższa odpowiedź Unnawuta jest najlepsza. Ale jeśli używasz prefiksu tabeli, musisz nieco zmienić kod.

function up()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NULL;');
}

Aby mieć pewność, że nadal możesz cofnąć migrację, my również to zrobimy down().

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Debiprasad
źródło