Как решить «Не удается добавить столбец NOT NULL со значением по умолчанию NULL» в SQLite3? - PullRequest
53 голосов
/ 03 июля 2010

Я получаю следующую ошибку при попытке добавить столбец NOT NULL в существующую таблицу. Почему это происходит? Я пробовал rake db: reset, думая, что существующие записи - это проблема, но даже после сброса БД проблема сохраняется. Не могли бы вы помочь мне разобраться в этом.

Файл миграции

class AddDivisionIdToProfile < ActiveRecord::Migration
  def self.up
    add_column :profiles, :division_id, :integer, :null => false
  end

  def self.down
    remove_column :profiles, :division_id
  end
end

Сообщение об ошибке

SQLite3 :: SQLException: невозможно добавить столбец NOT NULL со значением по умолчанию NULL: ALTER TABLE "профилирует" ДОБАВИТЬ "Division_id" целое число NOT NULL

Ответы [ 3 ]

154 голосов
/ 15 июля 2011

Это (что я бы рассмотрел) глюк с SQLite.Эта ошибка возникает независимо от того, есть ли в таблице какие-либо записи.

При добавлении таблицы с нуля вы можете указать NOT NULL, что вы и делаете с нотацией ": null => false",Тем не менее, вы не можете сделать это при добавлении столбца.В спецификации SQLite сказано, что для этого нужно иметь значение по умолчанию, что является плохим выбором.Добавление значения по умолчанию не является опцией, потому что оно устраняет необходимость иметь внешний ключ NOT NULL, а именно целостность данных.

Вот способ обойти этот глюк, и вы можете сделать все это одним и тем жемиграция.ПРИМЕЧАНИЕ: это для случая, когда у вас еще нет записей в базе данных.

class AddDivisionIdToProfile < ActiveRecord::Migration
  def self.up
    add_column :profiles, :division_id, :integer
    change_column :profiles, :division_id, :integer, :null => false
  end

  def self.down
    remove_column :profiles, :division_id
  end
end

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

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

36 голосов
/ 03 июля 2010

У вас уже есть строки в таблице, и вы добавляете новый столбец division_id. Ему нужно что-то в этом новом столбце в каждой из существующих строк.

SQLite обычно выбирает NULL, но вы указали, что оно не может быть NULL, так что это должно быть? У него нет возможности узнать.

См .:

Рекомендация этого блога заключается в добавлении столбца без ограничения not null, и он будет добавляться с NULL в каждой строке. Затем вы можете заполнить значения в division_id и затем использовать change_column, чтобы добавить ненулевое ограничение.

См. Блоги, на которые я ссылался, для описания скрипта миграции, который выполняет этот трехэтапный процесс.

6 голосов
/ 07 октября 2013

Если у вас есть таблица с существующими строками, вам необходимо обновить существующие строки перед добавлением ограничения null. Руководство по миграции рекомендует использовать локальную модель, например:

Рельсы 4 и выше:

class AddDivisionIdToProfile < ActiveRecord::Migration
  class Profile < ActiveRecord::Base
  end

  def change
    add_column :profiles, :division_id, :integer

    Profile.reset_column_information
    reversible do |dir|
      dir.up { Profile.update_all division_id: Division.first.id }
    end

    change_column :profiles, :division_id, :integer, :null => false
  end

end

Рельсы 3

class AddDivisionIdToProfile < ActiveRecord::Migration
  class Profile < ActiveRecord::Base
  end

  def change
    add_column :profiles, :division_id, :integer

    Profile.reset_column_information
    Profile.all.each do |profile|
      profile.update_attributes!(:division_id => Division.first.id)
    end

    change_column :profiles, :division_id, :integer, :null => false
  end

end
...