Изменение миграции Laravel, чтобы сделать столбец обнуляемым

194

Я создал миграцию с неподписанным user_id. Как я могу редактировать user_idв новой миграции, чтобы сделать это 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();
}
user391986
источник

Ответы:

267

Laravel 5 теперь поддерживает изменение столбца; Вот пример из официальной документации:

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

Источник: http://laravel.com/docs/5.0/schema#changing-columns

Laravel 4 не поддерживает изменение столбцов, поэтому вам нужно использовать другой метод, такой как написание необработанной команды SQL. Например:

// 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
источник
3
Спасибо за это. Но как я могу сделать обратное? Как изменить столбец, чтобы он не обнулялся? Любые идеи?
алгоритм
@algorhythm Пробуете ли вы эту '$ t-> string (' name ', 100) -> change ();'
MURATSPLAT
7
Вам нужно требовать доктрины \ dbal для миграции
younes0
33
@algorhythm ->nullable(false)позволит вам снова изменить столбец.
Колин
9
-> change () требует, чтобы вы установили пакет Doctrine DBAL, и он не распознает все те же типы столбцов, которые доступны из коробки от laravel. Например, double не является распознанным типом столбца для DBAL.
Уилл Винсент
175

Вот полный ответ для будущего читателя. Обратите внимание, что это возможно только в Laravel 5+.

Прежде всего вам понадобится пакет doctrine / dbal :

composer require doctrine/dbal

Теперь в вашей миграции вы можете сделать это, чтобы сделать столбец обнуляемым:

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

Вы можете быть удивлены, как отменить эту операцию. К сожалению, этот синтаксис не поддерживается:

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

Это правильный синтаксис для возврата миграции:

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

Или, если хотите, вы можете написать необработанный запрос:

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

Надеюсь, вы найдете этот ответ полезным. :)

Дмитрий Чеботарев
источник
4
Это наиболее полный ответ для L5, но следует отметить, что если 'user_id' является внешним ключом, каким он должен быть, вы не сможете изменить его, если не выполните команду 'DB :: Statement (' SET FOREIGN_KEY_CHECKS = 0 ');' первый. И установите его обратно в 1, когда вы закончите.
RZB
1
Спасибо, nullable(false)спас меня от выдергивания волос, потому что nullable()это плохо документировано, и нет никакой notNull()функции.
Зак Моррис
это не работает для внешних ключей с postgres. Попытка SET FOREIGN_KEY_CHECKS = 0дает ошибку. вам, вероятно, потребуется изменить ограничения таблицы с помощью необработанного запроса. смотрите здесь: postgresql.org/docs/current/static/sql-altertable.html
rrrafalsz
Это ломает мои тесты. Тесты начинают выполняться, а затем зависают. Я полагаю, это вызвано первым откатом. Вызывает зависание тестов для MySQL, а также для SQLite.
Томас Праксл
155

Я предполагаю, что вы пытаетесь отредактировать столбец, к которому уже добавлены данные, поэтому удаление столбца и добавление его снова в качестве столбца, допускающего обнуление, невозможно без потери данных. Мы будем alterсуществующий столбец.

Однако построитель схемы Laravel не поддерживает изменение столбцов, кроме переименования столбца. Таким образом, вам нужно будет выполнить необработанные запросы, чтобы сделать их, как это:

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

И чтобы убедиться, что вы все еще можете откатить миграцию, мы сделаем то же самое down().

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

Следует отметить, что, поскольку вы конвертируете между обнуляемыми и не обнуляемыми, вам необходимо убедиться, что вы очищаете данные до / после миграции. Так что сделайте это в вашем сценарии миграции двумя способами:

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
Для Laravel 4 замените queryнаstatement
Razor
2
Спасибо @Razor. Обновил мой ответ соответственно.
Unnawut
1
В downфункции во втором блоке кода оператор SQL должен заканчиваться на NOT NULL. ( downФункция в третьем примере правильная.)
Скотт Уэлдон,
47

Он полный переход на 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();
    });
}

Дело в том, что вы можете удалить nullable, передав falseв качестве аргумента.

Евгений Пракопчик
источник
16

Если вам случится изменить столбцы и наткнулся на

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

тогда просто установите

composer require doctrine/dbal

кругозор
источник
1
Это меня немного поразило, поэтому я
решил
9

Добавление к ответу Дмитрия Чеботарева, как и для Laravel 5+.

После запроса пакета доктрина / dbal :

composer require doctrine/dbal

Затем вы можете выполнить миграцию с пустыми столбцами, например:

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

Чтобы отменить операцию, выполните:

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

Добавление к Дмитрию Чеботареву Ответ,

Если вы хотите изменить несколько столбцов одновременно, вы можете сделать это, как показано ниже

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

Попытайся:

$table->integer('user_id')->unsigned()->nullable();
Адиль
источник
1
Это не меняет существующую колонку
dVaffection
9
вы забыли ->changeв конце и упомянуть только Laravel 5+
Александр Малахов
Вы должны требоватьcomposer require doctrine/dbal
Lizesh Shakya
2

Для Laravel 4.2 ответ Unnawut выше является лучшим. Но если вы используете префикс таблицы, то вам нужно немного изменить свой код.

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

И чтобы убедиться, что вы все еще можете откатить миграцию, мы сделаем то же самое down().

function down()
{
    $table_prefix = DB::getTablePrefix();
    DB::statement('ALTER TABLE `' . $table_prefix . 'throttle` MODIFY `user_id` INTEGER UNSIGNED NOT NULL;');
}
Debiprasad
источник