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

假设我有一个名为Transaction的模型,它具有:transaction_code属性。 我希望该属性自动填充可能与id不同的序列号(例如, id=1 Transaction可能具有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中生成这些序列号
  • 或任何其他方式,只要它的工作原理:-)

提前致谢。

目前,您可能会卡住并在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中看到这个纠正…但它确实可以解决问题。

如果要将默认值 INSERT语句中的列,可以使用关键字DEFAULT – no quotes:

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

或者你可以在你的情况下拼出默认的nextval(...) 。 请参阅此处的手册 。


这种情况的触发器很简单。 如果您想确保只输入序列中的数字,无论如何,这实际上就是我推荐的内容。

 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(); 

旁注:如果您想将自己的(非连续的)数字指定为“序列”,我已经在几天前的答案中为此编写了一个解决方案:
如何指定postgresql序列的值列表