使用 postgresql 恢复 rails 4 上的自动递增 id
Restore auto-increment id on rails 4 with postgresql
我需要将一些数据从旧网站迁移到新 rails 网站。我需要保留我的城市 ID,所以我创建了我的 table 并将 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
很明显我弄错了,你能帮我看看在哪里吗?我正在使用 rails 4 和 postgresql gem.
谢谢。
可能有更多 Rails-y 的方法来做到这一点,但是直接使用 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
P.S。下次您可以将序列创建留给 rails 并且在迁移数据时直接设置 id 值。然后当你完成时,更新序列的下一个值是一件简单的事情。
首先,关闭现有的 cities
table(当然,假设您还没有向其中添加任何新数据)。然后以正常方式创建 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
table 并以 id
作为主键,并且 id
将从序列中获得值。
接下来导入现有数据。这将为您提供一堆 id
值,而 cities.id
后面的序列不知道这些值,因此如果您尝试插入新城市,将会遇到问题。这很容易解决,使用 PostgreSQL 的 setval
function 在迁移中用一点 SQL 调整序列:
execute(%q{
select setval('cities_id_seq', (select max(id) from cities))
})
当您让 Rails 为 table 创建 id
PK 时,它会为 id
使用 serial
列。 serial
列或多或少是具有提供默认值的序列的 integer
列。对于名为 X
的 table,序列的名称将为 X_id_seq
,因此上面的名称为 cities_id_seq
。然后您想将序列的当前值设置为最大现有 cities.id
值,以便序列中的 next 值将比该最大值大 1。
我需要将一些数据从旧网站迁移到新 rails 网站。我需要保留我的城市 ID,所以我创建了我的 table 并将 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
很明显我弄错了,你能帮我看看在哪里吗?我正在使用 rails 4 和 postgresql gem.
谢谢。
可能有更多 Rails-y 的方法来做到这一点,但是直接使用 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
P.S。下次您可以将序列创建留给 rails 并且在迁移数据时直接设置 id 值。然后当你完成时,更新序列的下一个值是一件简单的事情。
首先,关闭现有的 cities
table(当然,假设您还没有向其中添加任何新数据)。然后以正常方式创建 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
table 并以 id
作为主键,并且 id
将从序列中获得值。
接下来导入现有数据。这将为您提供一堆 id
值,而 cities.id
后面的序列不知道这些值,因此如果您尝试插入新城市,将会遇到问题。这很容易解决,使用 PostgreSQL 的 setval
function 在迁移中用一点 SQL 调整序列:
execute(%q{
select setval('cities_id_seq', (select max(id) from cities))
})
当您让 Rails 为 table 创建 id
PK 时,它会为 id
使用 serial
列。 serial
列或多或少是具有提供默认值的序列的 integer
列。对于名为 X
的 table,序列的名称将为 X_id_seq
,因此上面的名称为 cities_id_seq
。然后您想将序列的当前值设置为最大现有 cities.id
值,以便序列中的 next 值将比该最大值大 1。