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

Ric*_*elo 8 postgresql activerecord ruby-on-rails save rails-postgresql

假设我有一个叫Transaction:transaction_code属性的模型.我希望该属性自动填充可能不同的序列号id(例如,id=1可能有的事务transaction_code=1000).

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

INSERT INTO transactions (transaction_code) VALUES (NULL);

这样做是在Transactions表上创建一个新行,其中transaction_code为NULL,而不是计算序列的nextval并将其插入相应的列.因此,正如我所知,如果你为postgres指定NULL,它假定你真的想要在该列中插入NULL,无论它是否具有默认值(我来自ORACLE,它具有不同的行为).

无论是在数据库上还是在RoR上,我都对此有任何解决方案:

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

提前致谢.

Eri*_*ott 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
Run Code Online (Sandbox Code Playgroud)

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


Erw*_*ter 2

如果要将默认值插入到语句中的列中INSERT,可以使用关键字DEFAULT- 无引号:

INSERT INTO mytable (col1, col2) VALUES (105, DEFAULT);
Run Code Online (Sandbox Code Playgroud)

或者您可以根据您的情况拼写出默认值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();
Run Code Online (Sandbox Code Playgroud)

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

  • 感谢埃尔文的回答。问题是,在 ActiveRecord 的 save 方法中,您无法在 INSERT 中“发送”关键字 DEFAULT (这可以解决问题,是的)。我更喜欢一个可以在 Ruby on Rails 应用程序中 100% 编码的解决方案,而不是在数据库上进行编程,这将使我无法在需要时无缝迁移到另一个 DBMS。 (2认同)