Alteração de migração do Laravel para tornar uma coluna anulável


194

Eu criei uma migração com não assinado user_id. Como posso editar user_idem uma nova migração para também fazer isso 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();
}

Respostas:


262

O Laravel 5 agora suporta a alteração de uma coluna; Aqui está um exemplo da documentação oficial:

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

Fonte: http://laravel.com/docs/5.0/schema#changing-columns

O Laravel 4 não suporta a modificação de colunas; portanto, você precisará usar outra técnica, como escrever um comando SQL bruto. Por exemplo:

// 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();
        });               

}

3
Thx por isso. Mas como posso fazer o oposto? Como alterar uma coluna para não ser anulável? Alguma ideia?
algorritmo

@algorhythm Você tenta esta '$ t-> string (' name ', 100) -> change ();'
MURATSPLAT

7
Você precisa exigir doutrina \ DBAL migrar
younes0

33
O @algorhythm ->nullable(false)permitirá que você altere a coluna novamente.
Colin

9
-> change () requer que você instale o pacote Doctrine DBAL, e ele não reconhece inerentemente todos os mesmos tipos de coluna que estão disponíveis prontamente na laravel. por exemplo, double não é um tipo de coluna reconhecido para o DBAL.
Will Vincent

174

Aqui está a resposta completa para o futuro leitor. Observe que isso só é possível no Laravel 5+.

Primeiro de tudo, você precisará do pacote doutrina / dbal :

composer require doctrine/dbal

Agora, na sua migração, você pode fazer isso para tornar a coluna anulável:

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

Você pode estar se perguntando como reverter esta operação. Infelizmente, esta sintaxe não é suportada:

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

Esta é a sintaxe correta para reverter a migração:

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

Ou, se preferir, você pode escrever uma consulta bruta:

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

Espero que você encontre esta resposta útil. :)


3
Esta é a resposta mais completa para L5, mas deve-se mencionar que se 'user_id' for uma chave estrangeira, como deveria ser, você não poderá alterá-la a menos que execute 'DB :: statement (' SET FOREIGN_KEY_CHECKS = 0 ');' primeiro. E volte para 1 quando terminar.
RZB

1
Obrigado, nullable(false)me salvou de arrancar os cabelos, porque nullable()não está bem documentado e não há notNull()função.
Zack Morris

isso não funciona para chaves estrangeiras no postgres. tentar SET FOREIGN_KEY_CHECKS = 0dá um erro. você provavelmente precisará alterar as restrições da tabela usando uma consulta bruta. veja aqui: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz

Isso está quebrando meus testes. Os testes começam a ser executados e depois são interrompidos. Suponho que a primeira reversão cause isso. Causa testes paralisados ​​para MySQL e SQLite.
21418 Thomas Praxl

155

Suponho que você esteja tentando editar uma coluna na qual já adicionou dados, portanto, não é possível soltar a coluna e adicioná-la novamente como uma coluna anulável sem perder dados. Nós vamos altera coluna existente.

No entanto, o construtor de esquemas do Laravel não suporta a modificação de colunas além de renomear a coluna. Portanto, você precisará executar consultas brutas para fazê-las, assim:

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

E para garantir que você ainda possa reverter sua migração, faremos o down()mesmo.

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

Uma observação é que, como você está convertendo entre anulável e não anulável, será necessário limpar os dados antes / após a migração. Faça isso no seu script de migração nos dois sentidos:

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

7
Para o Laravel 4, substitua queryporstatement
Razor

2
Obrigado @Razor. Atualizei minha resposta de acordo.
Unnawut

1
Na downfunção no segundo bloco de código, a instrução SQL deve terminar com NOT NULL. (A downfunção do terceiro exemplo é correcta.)
Scott Weldon

46

Ele é a migração completa para o Laravel 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();
    });
}

O ponto é que você pode remover nullablepassando falsecomo argumento.


16

Se acontecer de você mudar as colunas e tropeçar

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

então apenas instale

composer require doctrine/dbal


1
Isso me mordeu então eu fui em frente e fez a exceção / solução mais fácil de seguir: github.com/laravel/framework/pull/10002
Beau Simensen

9

Adicionando à resposta de Dmitri Chebotarev, como para o Laravel 5+.

Depois de exigir o pacote doutrina / dbal :

composer require doctrine/dbal

Você pode fazer uma migração com colunas anuláveis, da seguinte maneira:

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

Para reverter a operação, faça:

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

3

Adicionando à resposta de Dmitri Chebotarev,

Se você quiser alterar várias colunas ao mesmo tempo, faça o seguinte

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


2

Para o Laravel 4.2, a resposta de Unnawut acima é a melhor. Mas se você estiver usando o prefixo da tabela, precisará alterar um pouco o seu código.

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

E para garantir que você ainda possa reverter sua migração, faremos o down()mesmo.

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.