Cambio de migración de Laravel para hacer que una columna sea anulable

194

Creé una migración con unsigned user_id. ¿Cómo puedo editar user_iduna nueva migración para hacerla también 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();
}
usuario391986
fuente

Respuestas:

262

Laravel 5 ahora admite cambiar una columna; Aquí hay un ejemplo de la documentación oficial:

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

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

Laravel 4 no admite la modificación de columnas, por lo que necesitará usar otra técnica, como escribir un comando SQL sin formato. Por ejemplo:

// 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
fuente
3
Gracias por esto. Pero, ¿cómo puedo hacer lo contrario? ¿Cómo cambiar una columna para que no sea anulable? ¿Algunas ideas?
Algoritmo
@algoritmo ¿Prueba esto '$ t-> string (' nombre ', 100) -> change ();'
MURATSPLAT
77
Necesitas requerir doctrina \ dbal para migrar
younes0
33
@algorhythm ->nullable(false)le permitirá volver a cambiar la columna.
Colin
9
-> change () requiere que instales el paquete Doctrine DBAL, y no reconoce de manera inherente los mismos tipos de columna que están disponibles desde la caja de laravel ... por ejemplo, double no es un tipo de columna reconocido para DBAL.
Will Vincent
174

Aquí está la respuesta completa para el futuro lector. Tenga en cuenta que esto solo es posible en Laravel 5+.

En primer lugar, necesitará el paquete doctrine / dbal :

composer require doctrine/dbal

Ahora, en su migración, puede hacer esto para hacer que la columna sea anulable:

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

Quizás se pregunte cómo revertir esta operación. Lamentablemente, esta sintaxis no es compatible:

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

Esta es la sintaxis correcta para revertir la migración:

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

O, si lo prefiere, puede escribir una consulta sin procesar:

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 encuentre útil esta respuesta. :)

Dmitri Chebotarev
fuente
44
Esta es la respuesta más completa para L5, pero debe mencionarse que si 'user_id' es una clave foránea, que debería ser, no podrá cambiarla a menos que ejecute 'DB :: instrucción (' SET FOREIGN_KEY_CHECKS = 0 ');' primero. Y vuelva a establecerlo en 1 cuando haya terminado.
rzb
1
Gracias, nullable(false)me salvó de arrancarme el pelo, porque nullable()no está bien documentado y no tiene ninguna notNull()función.
Zack Morris el
esto no funciona para claves foráneas con postgres. intentar SET FOREIGN_KEY_CHECKS = 0da un error. Es probable que deba modificar las restricciones de la tabla mediante una consulta sin formato. ver aquí: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz
Esto está rompiendo mis pruebas. Las pruebas comienzan a ejecutarse y luego se bloquean. Supongo que la primera reversión causa esto. Provoca pruebas colgantes para MySQL y para SQLite.
Thomas Praxl
155

Supongo que está tratando de editar una columna en la que ya ha agregado datos, por lo que no es posible soltar la columna y agregarla nuevamente como una columna anulable sin perder datos. Vamos a alterla columna existente.

Sin embargo, el generador de esquemas de Laravel no admite la modificación de columnas que no sean renombrar la columna. Por lo tanto, deberá ejecutar consultas sin procesar para hacerlas, como esta:

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

Y para asegurarnos de que aún pueda revertir su migración, también haremos lo down()mismo.

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

Una nota es que, dado que está convirtiendo entre anulable y no anulable, deberá asegurarse de limpiar los datos antes / después de su migración. Así que hazlo en tu script de migración en ambos 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;');
}
Unnawut
fuente
77
Para Laravel 4, reemplace queryporstatement
Razor
2
Gracias @ Razor. Actualicé mi respuesta en consecuencia.
Unnawut
1
En la downfunción en el segundo bloque de código, la instrucción SQL debe terminar con NOT NULL. (La downfunción en el tercer ejemplo es correcta.)
Scott Weldon
46

Él es la migración completa para 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();
    });
}

El punto es que puedes eliminarlo nullablepasando falsecomo argumento.

Yauheni Prakopchyk
fuente
16

Si sucede que cambia las columnas y tropezó con

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

entonces solo instale

composer require doctrine/dbal

conocido
fuente
1
Esto me mordió, así que seguí adelante e hice que la excepción / solución fuera más fácil de seguir: github.com/laravel/framework/pull/10002
Beau Simensen
9

Agregando a la respuesta de Dmitri Chebotarev, como para Laravel 5+.

Después de requerir el paquete de doctrina / dbal :

composer require doctrine/dbal

Luego puede hacer una migración con columnas anulables, así:

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 revertir la operación, haga:

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
fuente
3

Agregando a la respuesta Dmitri Chebotarev,

Si desea modificar varias columnas a la vez, puede hacerlo como a continuación

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
fuente
2

Intentalo:

$table->integer('user_id')->unsigned()->nullable();
Adil
fuente
1
No altera la columna existente
dVaffection
9
te olvidaste ->changeal final y por mencionarlo solo Laravel 5+
Alexander Malakhov
Necesitas requerircomposer require doctrine/dbal
Lizesh Shakya
2

Para Laravel 4.2, la respuesta de Unnawut anterior es la mejor. Pero si está usando el prefijo de tabla, entonces necesita alterar un poco su código.

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

Y para asegurarnos de que aún pueda revertir su migración, también haremos lo down()mismo.

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