Миграция Laravel с SQLite "Невозможно добавить столбец NOT NULL со значением по умолчанию NULL"

Почему я получаю это предупреждение при использовании драйвера SQLite? У меня нет проблем с драйвером MySQL, но SQLite выдает эту ошибку.

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

Мои две миграции

ПЕРВАЯ МИГРАЦИЯ

  public function up() {
    Schema::create('users', function($table) {
      $table->increments('id');
      $table->string('username');
      $table->string('email');
      $table->string('password');
    });
  } 

ВТОРАЯ МИГРАЦИЯ

public function up() {
    Schema::table('users', function(Blueprint $table) {
        $table->date('birthday')->after('id');
        $table->string('last_name')->after('id');
        $table->string('first_name')->after('id');
    });
}

ОШИБКА

Exception: SQLSTATE[HY000]: General error: 1 Cannot add a NOT NULL column with default value NULL (SQL: alter table "users" add column "birthday" date not null)

Ответ 1

Похоже, это странность SQLite. Согласно ленточный форум Laracast о той же проблеме:

При добавлении таблицы с нуля вы можете указать NOT NULL. Однако при добавлении столбца это невозможно. Спецификация SQLite говорит, что для этого у вас есть значение по умолчанию, что является плохим выбором.

Посмотрев далее на SQLite ALTER TABLE docs, я обнаружил:

Если указано ограничение NOT NULL, то столбец должен иметь значение по умолчанию, отличное от NULL.

Я полагаю, что в мире SQLite не предоставление значения по умолчанию - это то же самое, что и значение по умолчанию должно быть NULL (в отличие от значения, которое не имеет значения по умолчанию для этого столбца с недействительным значением, поэтому значение должно быть предусмотренные для каждой вставки).

Кажется, SQLite просто оставляет вас в плохом состоянии, если вам нужно добавить столбец с недопустимыми значениями в существующую таблицу, в столбце которого также не должно быть значения по умолчанию.

Ответ 2

Если вы не хотите, чтобы столбец был nullable - тогда вам нужно сообщить Laravel о том, что должно быть по умолчанию.

Один из вариантов - это пустая строка "", подобная этой

public function up() {
    Schema::create('users', function($table) {
      $table->date('birthday')->after('id')->default('');
      $table->string('last_name')->after('id')->default('');
      $table->string('first_name')->after('id')->default('');

    });
  } 

Ответ 3

Я не знаком с Laravel, но, по-видимому, использование метода after для указания порядка столбцов указывает, что конкретно упоминается ТОЛЬКО MySQL (Laravel) и обсуждение (GitHub), похоже, указывает на трудности с использованием SQLite. Вероятно, это может быть несовместимо, поскольку его функция: "... использовать метод after to specify the order of columns" работает с ограничениями в документации SQLite (SQLite) для добавления столбцов..., который читает: "The new column is always appended to the end of the list of existing columns." Я не могу сказать, может ли вам присваивать значения по умолчанию с помощью ->default($value).

Ответ 4

Обходной путь, который я использовал успешно, - проверить, какой драйвер базы данных используется, и немного изменить миграцию для SQLite.

Например:

class MyMigration extends Migration
{
    public function up()
    {
        $driver = Schema::connection($this->getConnection())->getConnection()->getDriverName();

        Schema::table('invoices', function (Blueprint $table) use ($driver) {
            $table->string('stripe_invoice')->nullable()->change();

            if ('sqlite' === $driver) {
                $table->string('stripe_invoice_number')->default('');
            } else {
                $table->string('stripe_invoice_number')->after('stripe_invoice');
            }
        });
    }
}

Ответ 5

вам нужно добавить

->nullable()

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

Ответ 6

Другой способ обойти эту проблему - сначала создать поля со значением NULL, а затем изменить поля на NULL. Так, например, в этом случае мы сделаем что-то вроде следующего:

public function up() {
    // Create fields first as nullable
    Schema::table('users', function(Blueprint $table) {
        $table->date('birthday')->after('id')->nullable();
        $table->string('last_name')->after('id')->nullable();
        $table->string('first_name')->after('id')->nullable();
    });

    // Either truncate existing records or assign a value to new fields
    if (true) {
        DB::table('users')->truncate();
    } else {
        DB::table('users')->update([
            'birthday' => '2019-05-01',
            'last_name' => 'last name',
            'first_name' => 'first name',
        ]);
    }

    // Change the fields to not be null
    Schema::table('users', function(Blueprint $table) {
        $table->date('birthday')->nullable(false)->change();
        $table->string('last_name')->nullable(false)->change();
        $table->string('first_name')->nullable(false)->change();
    });
}