【问题标题】:Restore auto-increment id on rails 4 with postgresql使用 postgresql 在 Rails 4 上恢复自动增量 ID
【发布时间】:2015-01-06 18:39:10
【问题描述】:

我需要将一些数据从我们必须的旧网站迁移到新的 Rails 网站。我需要保留我的城市 ID,所以我创建了 id 设置为 false 的表并手动创建了该列:

create_table "cities", id: false, force: true do |t|
   t.integer  "id", null: false
   t.string   "name", null: false
   t.datetime "created_at"
   t.datetime "updated_at"
   t.boolean  "is_active",  default: true, null: false
   t.string   "code_che"
end

add_index "cities", ["id"], name: "index_cities_on_id", unique: true, using: :btree

完成迁移后,我希望能够创建新城市,例如 City.create(name: 'My big city') 但我收到下一个错误:

ActiveRecord::StatementInvalid: PG::NotNullViolation: ERROR:  null value in column "id" violates not-null constraint

很明显我犯了一个错误,你能帮我找出哪里吗?我正在使用带有 postgresql gem 的 rails 4。

谢谢。

【问题讨论】:

    标签: ruby-on-rails postgresql rails-migrations


    【解决方案1】:

    可能有一种更符合 Rails 的方式来执行此操作,但您需要使用直接 SQL 来执行此操作。将“12345”替换为“id”的当前最大值大一。

    CREATE SEQUENCE cities_id_seq START WITH 12345;
    ALTER TABLE cities ALTER COLUMN id SET DEFAULT 'nextval(''cities_id_seq''::regclass)';
    ALTER TABLE cities ALTER COLUMN id SET NOT NULL;
    

    您可以像这样将其放入 Rails 迁移中:

    def up
      execute %Q{
        CREATE SEQUENCE cities_id_seq START WITH 12345;
        ALTER TABLE cities ALTER COLUMN id SET DEFAULT 'nextval(''cities_id_seq''::regclass)';
        ALTER TABLE cities ALTER COLUMN id SET NOT NULL;
      }
    end
    

    附:下次您可以将序列创建留给 rails,当您迁移数据时,只需直接设置 id 值。然后,当您完成后,只需更新序列的下一个值即可。

    【讨论】:

    • 谢谢你,它就像一个魅力。我只需要删除第二行中最外面的单引号。干杯。
    【解决方案2】:

    首先,关闭您现有的cities 表(当然,假设您没有向其中添加任何新数据)。然后以正常方式创建cities:

    create_table "cities", force: true do |t|
       t.string   "name", null: false
       t.datetime "created_at"
       t.datetime "updated_at"
       t.boolean  "is_active",  default: true, null: false
       t.string   "code_che"
    end
    

    这将为您提供一个普通的 cities 表,其中包含一个 id 作为主键,id 将从一个序列中获得值。

    接下来导入现有数据。这将为您提供一堆 id 值,cities.id 后面的序列不知道,因此如果您尝试插入新城市,您会遇到问题。使用 PostgreSQL 的 setval function 在迁移中通过一些 SQL 调整序列很容易解决这个问题:

    execute(%q{
      select setval('cities_id_seq', (select max(id) from cities))
    })
    

    当您让 Rails 为表创建 id PK 时,它将为 id 使用 serial 列。 serial 列或多或少是一个 integer 列,具有提供默认值的序列。对于名为X 的表,序列的名称将是X_id_seq,因此上面的cities_id_seq 名称。然后,您希望将序列的当前值设置为现有的最大 cities.id 值,以便序列中的 下一个 值将比该最大值大一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-10-21
      • 2017-07-20
      • 2014-08-10
      • 2020-09-05
      • 1970-01-01
      • 2018-02-11
      • 1970-01-01
      • 2012-02-08
      相关资源
      最近更新 更多