我之前在迁移中创建了一个日期列并将其设置为可空。现在我想将其更改为不可空。假设数据库中有空行,我该怎么做?如果当前为空,我可以将这些列设置为 Time.now。
我之前在迁移中创建了一个日期列并将其设置为可空。现在我想将其更改为不可空。假设数据库中有空行,我该怎么做?如果当前为空,我可以将这些列设置为 Time.now。
如果您希望在迁移中执行此操作,则可以按照以下方式进行:
# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)
# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false
change_column_null :my_models, :date_column, false
NULL
值的记录,您可以传递第四个参数,该参数是在记录中使用 NULL
值时要使用的默认值:change_column_null :my_models, :date_column, false, Time.now
change_column_null
加 1。然而,Rick Smith 上面的评论指出了一个非常有效的情况。 - kingsfoilchange_column_null
不会为列设置默认值。如果您需要这样做,我建议首先使用 update_all
更新所有 null
记录,然后改用 change_column :table, :column, :column_type, default: "yourmom", null: false
。这样更清晰,甚至可能更快/更少阻塞。 - Joshua Pinterdef change
change_column_null(:users, :admin, false, <put a default value here> )
# change_column(:users, :admin, :string, :default => "")
end
change_column_null
中的第4个值正是如此。有关更多详细信息,请参见documentation。add_column :users, :admin, :string
然后
change_column_null(:admin, :string, false, "new_value_for_existing_records")
- colsen:default =>
值的 change_column
语句。change_column :my_table, :my_column, :integer, :default => 0, :null => false
根据数据库引擎的不同,可能需要使用 change_column_null
change_column_null
。 - jessecurrydef change
change_column_null(:users, :admin, false )
end
根据文档,在Rails 4.02+中没有像update_all
这样带有两个参数的方法。取而代之,可以使用以下代码:
# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)
# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false
change_column_null
是个坏主意,因为它会在检查所有记录时阻止读写操作。
处理这些迁移(Postgres特定)的推荐方法是将此过程分为两个迁移。
一个用于更改带有约束的表:
class SetSomeColumnNotNull < ActiveRecord::Migration[6.0]
def change
safety_assured do
execute 'ALTER TABLE "users" ADD CONSTRAINT "users_some_column_null" CHECK ("some_column" IS NOT NULL) NOT VALID'
end
end
end
还需要单独进行验证的迁移:
class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
def change
safety_assured do
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
end
end
end
NOT NULL
添加到架构中,然后在运行验证后删除约束:class ValidateSomeColumnNotNull < ActiveRecord::Migration[6.0]
def change
safety_assured do
execute 'ALTER TABLE "users" VALIDATE CONSTRAINT "users_some_column_null"'
end
# in Postgres 12+, you can then safely set NOT NULL on the column
change_column_null :users, :some_column, false
safety_assured do
execute 'ALTER TABLE "users" DROP CONSTRAINT "users_some_column_null"'
end
end
end
NOT NULL
,因此我建议设置模型级别验证以要求值存在(尽管我建议即使对于允许此步骤的PG版本也是如此)。null
。如果您有现有记录,则无法同时使用add_timestamps和null:false,因此这里是解决方案:
def change
add_timestamps(:buttons, null: true)
Button.find_each { |b| b.update(created_at: Time.zone.now, updated_at: Time.zone.now) }
change_column_null(:buttons, :created_at, false)
change_column_null(:buttons, :updated_at, false)
end
Button.where(created_at: nil).update_all(created_at: Time.zone.now)
这样的方式,因为它比循环并在每个记录上调用 update
更快。 - Ollie BennettButton.where(created_at: nil).update_all(created_at: Time.zone.now)
这样的写法,因为它比循环并在每个记录上调用update
要快。 - Ollie Bennett
MyModel.update_all({:date_column => Time.now}, {:date_column => nil})
。在原始形式中的查询只会使所有模型在该字段上具有空值。 - dimitarvp