Rails 和 Postgres:迁移到 change_colomn 时出现错误“无法强制转换为没有时区的时间戳”
Posted
技术标签:
【中文标题】Rails 和 Postgres:迁移到 change_colomn 时出现错误“无法强制转换为没有时区的时间戳”【英文标题】:Rails & Postgres: Migration to change_colomn gives error "cannot be cast to type timestamp without time zone" 【发布时间】:2011-04-02 10:08:40 【问题描述】:将“deleted_at”时间列转换为日期时间列的 Rails 迁移失败。关于如何解决这个问题的任何想法?如果相关,它是 Postgres 的全新安装。
-- change_column(:products, :deleted_at, :datetime)
PGError: ERROR: column "deleted_at" cannot be cast to type timestamp without time zone
: ALTER TABLE "products" ALTER COLUMN "deleted_at" TYPE timestamp
【问题讨论】:
【参考方案1】:在 Rails 中,这看起来像
class ChangeStatusUpdatedAtToDateTime < ActiveRecord::Migration
def up
remove_column :bookings, :status_updated_at
add_column :bookings, :status_updated_at, :datetime
end
def down
remove_column :bookings, :status_updated_at
add_column :bookings, :status_updated_at, :time
end
end
如果您有想要传输的数据,可以使用以下代码(未经测试!):
class ChangeStatusUpdatedAtToDateTime < ActiveRecord::Migration
def up
add_column :bookings, :temp_status_updated_at, :datetime
Booking.update_all("temp_status_updated_at = updated_at")
remove_column :bookings, :status_updated_at
rename_column :bookings, :temp_status_updated_at, :status_updated_at
end
def down
add_column :bookings, :temp_status_updated_at, :time
Booking.update_all("temp_status_updated_at = updated_at")
remove_column :bookings, :status_updated_at
rename_column :bookings, :temp_status_updated_at, :status_updated_at
end
end
【讨论】:
如果列中已有数据,您会怎么做? 添加了一个例子@RogerPerez【参考方案2】:您不能将字段的类型从时间更改为时间戳(“日期时间”),因为无法转换值 - 数据库不知道日期。
但是,您可以删除并重新创建该列:
ALTER TABLE products DROP COLUMN deleted_at;
ALTER TABLE products ADD COLUMN deleted_at timestamp;
或者如果此字段设置为 NOT NULL,您应该改为:
ALTER TABLE products ADD COLUMN deleted_at timestamp NOT NULL;
但是如果你像 Sean 一样坚持在这个表中保留假值,你可以像这样使用 ALTER...TYPE...USING:
ALTER TABLE products ALTER COLUMN deleted_at TYPE timestamp USING
CASE WHEN deleted_at IS NOT NULL THEN timestamp '1970-01-01 00:00:00' END;
-- Or:
ALTER TABLE products ALTER COLUMN deleted_at
TYPE timestamp USING date '1970-01-01' + deleted_at;
【讨论】:
但这也会删除deleted_at中的所有值。这怎么可能解决? @OtoBrglez 这些值一开始就没什么用——旧的列类型只存储一天中的时间,而不是日期。没有合理的方法将它们转换为日期时间。 这是一个糟糕的解决方案。许多系统使用deleted_at
来确定产品是否被删除。删除列并阅读具有取消删除这些记录的副作用!
@Sean 我认为为这样的混乱数据类型付出的代价是合理的 :) 但我为您的用例更新了答案。以上是关于Rails 和 Postgres:迁移到 change_colomn 时出现错误“无法强制转换为没有时区的时间戳”的主要内容,如果未能解决你的问题,请参考以下文章
Ruby on Rails + Postgres 迁移从每个 db 上的 schema.rb 中删除 enable_extension "pgcrypto":migrate