如何使用 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