为字段创建 PostgreSQL 序列(不是记录的 ID)

问题描述 投票:0回答:2

我正在开发 Ruby on Rails 应用程序。我们正在使用 PostgreSQL 数据库。

有一个名为

scores
的表,其中包含以下列:

Column        | Type
--------------+-----------------------
id            | integer
value         | double precision
ran_at        | timestamp
active        | boolean
build_id      | bigint
metric_id     | integer
platform_id   | integer
mode_id       | integer
machine_id    | integer
higher_better | boolean
job_id        | integer
variation_id  | integer
step          | character varying(255)

我需要向job_id添加一个

序列
(注意:
job
没有模型)。

如何创建这个序列?

ruby-on-rails postgresql activerecord rails-activerecord rails-postgresql
2个回答
37
投票

使用

CREATE SEQUENCE

CREATE SEQUENCE scores_job_id_seq;  -- = default name for plain a serial

然后添加一列默认值到

scores.job_id

ALTER TABLE scores ALTER COLUMN job_id
SET DEFAULT nextval('scores_job_id_seq');

要将序列“绑定”到列(因此当删除列时它也会被删除),还运行:

ALTER SEQUENCE scores_job_id_seq OWNED BY scores.job_id;

所有这些都可以替换为首先使用列 serial 的伪数据类型

job_id
。参见:

如果您的表格已有行,您可能需要将

SEQUENCE
设置为当前最大值:

SELECT setval('scores_job_id_seq', COALESCE(max(job_id), 1)) FROM scores;

唯一剩下的区别:

serial
列也设置为
NOT NULL
。你可能也想要那个。如果存在任何空值,请首先使用序列值更新:

UPDATE scores
SET    job_id = nextval('scores_job_id_seq')
WHERE  job_id IS NULL;

最后:

ALTER TABLE scores ALTER COLUMN job_id SET NOT NULL;

相关:

但是不能只改变现有

integer
的类型:

ALTER TABLE scores ALTER job_id TYPE serial;

serial
不是实际的数据类型。这只是
CREATE TABLE
的一个符号化便利功能。
在 Postgres 10 或更高版本中,请考虑使用
IDENTITY
列:


22
投票

所以我想出了如何在 Ruby on Rails 上使用 ActiveRecord 迁移来做到这一点。我基本上使用了 Erwin 的命令和此页面的帮助,并将它们放入迁移文件中。这些是步骤:

1. 在终端中输入:

rails g migration CreateJobIdSequence
rails g migration AddJobIdSequenceToScores

2. 编辑迁移文件如下:

20140709181616_create_job_id_sequence.rb

class CreateJobIdSequence < ActiveRecord::Migration
  def up
    execute <<-SQL
      CREATE SEQUENCE job_id_seq;
    SQL
  end

  def down
    execute <<-SQL
      DROP SEQUENCE job_id_seq;
    SQL
  end
end

20140709182313_add_job_id_sequence_to_scores.rb

class AddJobIdSequenceToScores < ActiveRecord::Migration
  def up
    execute <<-SQL
      ALTER SEQUENCE job_id_seq OWNED BY scores.job_id;
      ALTER TABLE scores ALTER COLUMN job_id SET DEFAULT nextval('job_id_seq');
    SQL
  end

  def down
    execute <<-SQL
      ALTER SEQUENCE job_id_seq OWNED BY NONE;
      ALTER TABLE scores ALTER COLUMN job_id SET NOT NULL;
    SQL
  end
end

3. 迁移数据库。在终端中输入:

rake db:migrate
© www.soinside.com 2019 - 2024. All rights reserved.