Ruby on Rails+PostgreSQL:自定义序列的使用

Posted

技术标签:

【中文标题】Ruby on Rails+PostgreSQL:自定义序列的使用【英文标题】:Ruby on Rails+PostgreSQL: usage of custom sequences 【发布时间】:2011-10-19 11:40:15 【问题描述】:

假设我有一个名为 Transaction 的模型,它有一个 :transaction_code 属性。 我希望该属性自动填充一个可能与id 不同的序列号(例如,id=1 的交易可能有transaction_code=1000)。

我尝试在 postgres 上创建一个序列,然后将 transaction_code 列的默认值设为该序列的 nextval。 问题是,如果我没有在 RoR 上为 @transaction.transaction_code 分配任何值,当我在 RoR 上发出 @transaction.save 时,它会尝试执行以下 SQL:

INSERT INTO transactions (transaction_code) VALUES (NULL);

这样做是在 Transactions 表上创建一个新行,其中 transaction_code 为 NULL,而不是计算序列的 nextval 并将其插入相应的列。因此,正如我发现的那样,如果您为 postgres 指定 NULL,它假定您确实想将 NULL 插入该列,而不管它是否具有默认值(我来自具有不同行为的 ORACLE)。

我愿意接受任何解决方案,无论是在数据库上还是在 RoR 上完成:

有一种方法可以从 ActiveRecord 中排除属性 save 或者有一种方法可以在使用触发器插入之前更改列的值 或者有一种方法可以在 RoR 中生成这些序列号 或任何其他方式,只要它有效:-)

提前致谢。

【问题讨论】:

【参考方案1】:

目前,您可能无法像这样在 ROR 模型中获取和分配序列:

before_create :set_transaction_code_sequence

def set_transaction_code_sequence
  self.transaction_code = self.class.connection.select_value("SELECT nextval('transaction_code_seq')")
end

我不是特别喜欢这个解决方案,因为我想直接在 AR 中看到这个解决方案......但它确实可以解决问题。

【讨论】:

这确实为数据库创建了一个额外的查询,我希望能够在一个查询中插入序列值。【参考方案2】:

如果您想在INSERT 语句的列中插入默认值,您可以使用关键字DEFAULT - 不带引号:

INSERT INTO mytable (col1, col2) VALUES (105, DEFAULT);

或者您可以拼出默认值 nextval(...) 在您的情况下。请参阅manual here。


这种情况的触发器很简单。如果您想确保只输入序列中的数字,这实际上是我的建议。

CREATE OR REPLACE FUNCTION trg_myseq()
  RETURNS trigger AS
$BODY$
BEGIN

NEW.mycol := nextval('my_seq');
RETURN NEW;

END;
$BODY$
  LANGUAGE plpgsql VOLATILE;

CREATE TRIGGER myseq
  BEFORE INSERT
  ON mytable
  FOR EACH ROW
  EXECUTE PROCEDURE trg_myseq();

附带说明: 如果您想将自己的(非顺序)数字分配为“序列”,我已经在几天前的答案中为此编写了一个解决方案:How to specify list of values for a postgresql sequence

【讨论】:

感谢欧文的回答。问题是,在 ActiveRecord 的保存方法中,您不能在 INSERT 中“发送”关键字 DEFAULT(这样可以解决问题,是的)。我更喜欢可以 100% 编码在 Ruby on Rails 应用程序中的解决方案,而不是在数据库上对其进行编程,如果需要,这将使我无法无缝迁移到另一个 DBMS。 @Ricardo:“无缝迁移到另一个 DBMS”是一个美好的幻想,但它与现实并没有太大关系,抱歉。触发器的一大缺点是您无法在 Heroku 共享数据库上使用它。

以上是关于Ruby on Rails+PostgreSQL:自定义序列的使用的主要内容,如果未能解决你的问题,请参考以下文章

Ruby on Rails+PostgreSQL:自定义序列的使用

设置默认值时出现空约束错误 Ruby On Rails - Postgresql

在 Ruby on Rails 3.2.14 / Ruby 2.0.0 / PostgreSQL 9.2.4 中使用 activerecord 从序列中检索 nextval

将重复的SQL模型复制到Ruby on Rails postgresql模型中

使用 postgresql 和 ruby​​ on rails 优化时间序列数据检索的数据库查询

Heroku上的现有Ruby on Rails Web应用程序(PostgreSQL),Devise身份验证,需要为移动支持添加Rails API