如何使用 Rails/ActiveRecord 将 postgreSQL 中的主键类型更改为 bigserial
How to change primary key type in postgreSQL to bigserial using Rails/ActiveRecord
如何在 postgres 中将现有 table 的主键列的类型从 serial
(int) 更改为 bigserial
(bigint)?
该数据库由 Rails 应用程序使用。我需要对应用程序进行任何更改吗?
创建迁移:
bundle exec rails generate migration ChangeSerialToBigserial
编辑迁移文件:
def up
execute "ALTER TABLE my_table ALTER COLUMN id SET DATA TYPE bigint"
end
登录 rails dbconsole
(它只是 psql
控制台,只为您的应用程序选择了一个数据库):
bundle exec rails dbconsole
检查table:
# \d my_table
Table "public.my_table"
Column | Type | Modifiers
------------------------+-----------------------------+----------------------------------------------------
id | bigint | not null default nextval('my_table_id_seq'::regclass)
与迁移文件中相同的 sql
查询,您可以 运行 直接从 psql
:
my_database=# ALTER TABLE my_table ALTER COLUMN id SET DATA TYPE bigint;
正如 建议的那样 任何引用 my_table.id 的列也必须更改。 这意味着如果您有 Post
my_table_id
的模型也应该更改。
class ConvertIntToBigint < ActiveRecord::Migration[5.1]
def up
query = <<-SQL
SELECT tablename AS "tablename"
FROM pg_tables
WHERE schemaname = 'public';
SQL
connection.execute(query).each do |element|
if column_exists?(element['tablename'], :id, :integer)
change_table(element['tablename']) {|t| t.change :id, :bigint }
end
end
end
def down
end
end
我相信接受的答案只是故事的一半。您还必须修改序列。
特别是,仅更改 id 列的类型后,您仍然有:
# \d my_table_id_seq
Sequence "public.my_table_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+---------+------------+-----------+---------+-------
integer | 1 | 1 | 2147483647 | 1 | no | 1
然后你需要运行alter sequence mytable_id_seq as bigint;
结果是:
# \d my_table_id_seq
Sequence "public.my_table_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
@I0Result 答案的扩展版本,这也改变了序列和(大多数)外键:
class ConvertIntToBigint < ActiveRecord::Migration[6.0]
def up
query = <<-SQL
SELECT tablename AS "tablename"
FROM pg_tables
WHERE schemaname = 'public';
SQL
tablenames = connection.execute(query).map { |r| r['tablename'] }
tablenames.each do |tablename|
next if ["schema_migrations", "ar_internal_metadata"].include?(tablename)
# change any "id" columns and their sequences to bigint
if column_exists?(tablename, :id, :integer)
change_table(tablename) { |t| t.change :id, :bigint }
connection.execute("alter sequence #{tablename}_id_seq as bigint")
end
# try to find any associations that use a foreign key and change that to bigint, too
model = begin
tablename.classify.constantize
rescue StandardError => e # join tables have no model
nil
end
if model and model.ancestors.include?(ActiveRecord::Base)
model.reflect_on_all_associations.each do |assoc|
foreign_key_name = assoc.foreign_key
if column_exists?(tablename, foreign_key_name, :integer)
change_table(tablename) { |t| t.change foreign_key_name, :bigint }
end
end
end
end
end
def down
end
end
如何在 postgres 中将现有 table 的主键列的类型从 serial
(int) 更改为 bigserial
(bigint)?
该数据库由 Rails 应用程序使用。我需要对应用程序进行任何更改吗?
创建迁移:
bundle exec rails generate migration ChangeSerialToBigserial
编辑迁移文件:
def up
execute "ALTER TABLE my_table ALTER COLUMN id SET DATA TYPE bigint"
end
登录 rails dbconsole
(它只是 psql
控制台,只为您的应用程序选择了一个数据库):
bundle exec rails dbconsole
检查table:
# \d my_table
Table "public.my_table"
Column | Type | Modifiers
------------------------+-----------------------------+----------------------------------------------------
id | bigint | not null default nextval('my_table_id_seq'::regclass)
与迁移文件中相同的 sql
查询,您可以 运行 直接从 psql
:
my_database=# ALTER TABLE my_table ALTER COLUMN id SET DATA TYPE bigint;
正如 Post
my_table_id
的模型也应该更改。
class ConvertIntToBigint < ActiveRecord::Migration[5.1]
def up
query = <<-SQL
SELECT tablename AS "tablename"
FROM pg_tables
WHERE schemaname = 'public';
SQL
connection.execute(query).each do |element|
if column_exists?(element['tablename'], :id, :integer)
change_table(element['tablename']) {|t| t.change :id, :bigint }
end
end
end
def down
end
end
我相信接受的答案只是故事的一半。您还必须修改序列。
特别是,仅更改 id 列的类型后,您仍然有:
# \d my_table_id_seq
Sequence "public.my_table_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
---------+-------+---------+------------+-----------+---------+-------
integer | 1 | 1 | 2147483647 | 1 | no | 1
然后你需要运行alter sequence mytable_id_seq as bigint;
结果是:
# \d my_table_id_seq
Sequence "public.my_table_id_seq"
Type | Start | Minimum | Maximum | Increment | Cycles? | Cache
--------+-------+---------+---------------------+-----------+---------+-------
bigint | 1 | 1 | 9223372036854775807 | 1 | no | 1
@I0Result 答案的扩展版本,这也改变了序列和(大多数)外键:
class ConvertIntToBigint < ActiveRecord::Migration[6.0]
def up
query = <<-SQL
SELECT tablename AS "tablename"
FROM pg_tables
WHERE schemaname = 'public';
SQL
tablenames = connection.execute(query).map { |r| r['tablename'] }
tablenames.each do |tablename|
next if ["schema_migrations", "ar_internal_metadata"].include?(tablename)
# change any "id" columns and their sequences to bigint
if column_exists?(tablename, :id, :integer)
change_table(tablename) { |t| t.change :id, :bigint }
connection.execute("alter sequence #{tablename}_id_seq as bigint")
end
# try to find any associations that use a foreign key and change that to bigint, too
model = begin
tablename.classify.constantize
rescue StandardError => e # join tables have no model
nil
end
if model and model.ancestors.include?(ActiveRecord::Base)
model.reflect_on_all_associations.each do |assoc|
foreign_key_name = assoc.foreign_key
if column_exists?(tablename, foreign_key_name, :integer)
change_table(tablename) { |t| t.change foreign_key_name, :bigint }
end
end
end
end
end
def down
end
end