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

Ruby on Rails 迁移 - 创建新的数据库模式

如何在 Rails 3 的 Postgres 数据库中使用枚举? [关闭]

如何在 Rails 迁移中添加检查约束?

Django 从 MySQL 迁移到 Postgres

PostgreSQL:在 Rails 迁移中使用 add_column "after" 选项