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

时间:2011-10-19 11:40:16

标签: ruby-on-rails postgresql activerecord save rails-postgresql

假设我有一个名为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
  • 中生成这些序列号
  • 或任何其他方式,只要它有效: - )

提前致谢。

2 个答案:

答案 0 :(得分:6)

目前,您可能会陷入困境并在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中看到这个问题......但它确实可以解决这个问题。

答案 1 :(得分: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