318

I created a migration with unsigned user_id. How can I edit user_id in a new migration to also make it 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();
}
kjones
  • 1,339
  • 1
  • 13
  • 28
user391986
  • 29,536
  • 39
  • 126
  • 205

12 Answers12

419

Laravel 5 now supports changing a column; here's an example from the offical documentation:

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

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

Laravel 4 does not support modifying columns, so you'll need use another technique such as writing a raw SQL command. For example:

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

}
kjones
  • 1,339
  • 1
  • 13
  • 28
MURATSPLAT
  • 4,650
  • 1
  • 13
  • 12
  • 4
    Thx for this. But how can I make the opposite? How to change a column to not be nullable? Any ideas? – algorhythm Apr 28 '15 at 13:28
  • @algorhythm Do you try this ' $t->string('name', 100)->change();' – MURATSPLAT May 01 '15 at 15:45
  • @MURATSPLAT No, I did it with `DB::statement` and raw SQL... But maybe I'll try it later... Thx – algorhythm May 01 '15 at 15:48
  • 11
    You need to require doctrine\dbal to migrate – younes0 Dec 16 '15 at 16:04
  • 51
    @algorhythm `->nullable(false)` will let you change the column back again. – Colin Feb 09 '16 at 22:20
  • 10
    ->change() requires you to install the Doctrine DBAL package, and it does not inherently recognize all the same column types that are available out of the box from laravel.. for example double is not a recognized column type to DBAL. – Will Vincent May 09 '16 at 15:53
  • It would not work if you try to rename column in the same function, you need to run 2 functions on the same table to perform rename and changing. – Yevgeniy Afanasyev Mar 16 '17 at 01:00
  • @MURATSPLAT: I have same problem and while I add the doctrine/dbal dependency to my composer.json file, `change` method isn't recognized and don't work.I install Laravel 5.7. – maryam Oct 13 '18 at 16:49
  • Hello @sarina I have looked up official Laravel doc and I can see there is no change. Did you read it ? https://laravel.com/docs/5.7/migrations#modifying-columns What is the error if the method is not working.. – MURATSPLAT Oct 15 '18 at 05:12
  • @MURATSPLAT. Hi. My problem solved. I should write edited column in a new migration file and migrate it but I migrate previous migration file. – maryam Oct 15 '18 at 09:05
227

Note that this is only possible in Laravel 5+.

First of all you'll need the doctrine/dbal package:

composer require doctrine/dbal

Now in your migration you can do this to make the column nullable:

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

You may be wondering how to revert this operation. Sadly this syntax is not supported:

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

This is the correct syntax to revert the migration:

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

Or, if you prefer, you can write a raw query:

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;');
}
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
Dmitri Chebotarev
  • 2,429
  • 1
  • 11
  • 7
  • 6
    This is the most complete answer for L5, but it should be mentioned that if 'user_id' is a foreign key, which it should be, you won't be able to change it unless you run 'DB::statement('SET FOREIGN_KEY_CHECKS = 0');' first. And set it back to 1 when you're done. – rzb Jan 15 '16 at 15:21
  • 3
    Thank you, `nullable(false)` saved me from pulling my hair out, because `nullable()` is not well documented, and there is no `notNull()` function. – Zack Morris Nov 30 '16 at 21:38
  • this doesn't work for foreign keys with postgres. trying `SET FOREIGN_KEY_CHECKS = 0` gives an error. you will likely need to alter the table's constraints by using a raw query. see here: https://www.postgresql.org/docs/current/static/sql-altertable.html – szaman Jun 07 '17 at 08:00
  • This is breaking my tests. The tests start to run and then hang. I suppose the first rollback causes this. Causes hanging tests for MySQL as well as for SQLite. – Thomas Praxl Jul 19 '18 at 11:49
  • doctrine/dbal isn't required if use raw queries – Nikolay Shabak Dec 10 '22 at 12:59
166

I assume that you're trying to edit a column that you have already added data on, so dropping column and adding again as a nullable column is not possible without losing data. We'll alter the existing column.

However, Laravel's schema builder does not support modifying columns other than renaming the column. So you will need to run raw queries to do them, like this:

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

And to make sure you can still rollback your migration, we'll do the down() as well.

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

One note is that since you are converting between nullable and not nullable, you'll need to make sure you clean up data before/after your migration. So do that in your migration script both ways:

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
  • 7,500
  • 1
  • 26
  • 33
54

He're the full migration for 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();
    });
}

The point is, you can remove nullable by passing false as an argument.

Yauheni Prakopchyk
  • 10,202
  • 4
  • 33
  • 37
29

Adding to Dmitri Chebotarev's answer, as for Laravel 5+.

After requiring the doctrine/dbal package:

composer require doctrine/dbal

You can then make a migration with nullable columns, like so:

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

To revert the operation, do:

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');
}
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
rzb
  • 2,077
  • 6
  • 22
  • 31
16

If you happens to change the columns and stumbled on

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

then just install

composer require doctrine/dbal

ken
  • 13,869
  • 6
  • 42
  • 36
  • 1
    This bit me so I went ahead and made the exception / solution easier to follow: https://github.com/laravel/framework/pull/10002 – Beau Simensen Aug 21 '15 at 18:28
9

I had to use nullable(true)

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

Install Composer Package:

composer require doctrine/dbal

After successfully install composer package we can change data type and change column name using migration command.

Syntax:

php artisan make:migration alter_table_[table_name]_change_[column_name] --table=[table_name]

Example:

php artisan make:migration alter_table_sessions_change_user_id --table=sessions

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AlterTableSessionsChangeUserId extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('sessions', function (Blueprint $table) {
            $table->integer('user_id')->unsigned()->nullable()->change();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('sessions', function (Blueprint $table) {
            $table->dropColumn('user_id');
        });
    }
}

And run: php artisan migrate

OR

Or table refresh to change column name. not use change method.

Schema::create('throttle', function(Blueprint $table)
{
    $table->increments('id');
    # old code
    $table->integer('user_id')->unsigned();
    # new code
    $table->integer('user_id')->unsigned()->nullable();
}

Note: Below command to clear data from table.

php artisan migrate:refresh --path=/database/migrations/2021_09_31_050851_create_throttle_table.php
Fefar Ravi
  • 794
  • 7
  • 18
3

Adding to Dmitri Chebotarev Answer,

If you want to alter multiple columns at a time , you can do it like below

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
  • 1,764
  • 4
  • 16
  • 21
2

Try it:

$table->integer('user_id')->unsigned()->nullable();
Adil
  • 1,008
  • 11
  • 21
2

For Laravel 4.2, Unnawut's answer above is the best one. But if you are using table prefix, then you need to alter your code a little.

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

And to make sure you can still rollback your migration, we'll do the down() as well.

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Debiprasad
  • 5,895
  • 16
  • 67
  • 95
0

you need first install doctrine/dbal package.

composer require doctrine/dbal

and then use change() method for example:

Schema::table('posts', function (Blueprint $table) {
    $table->unsignedBigInteger('user_id')->nullable()->change();
});
Hossein Shafiei
  • 111
  • 1
  • 3