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

发布于 2024-12-10 14:55:28 字数 877 浏览 0 评论 0原文

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

谢谢进步。

Say I have a model called Transaction which has a :transaction_code attribute.
I want that attribute to be automatically filled with a sequence number which may differ from id (e.g. Transaction with id=1 could have transaction_code=1000).

I have tried to create a sequence on postgres and then making the default value for the transaction_code column the nextval of that sequence.
The thing is, if I do not assign any value to @transaction.transaction_code on RoR, when I issue a @transaction.save on RoR, it tries to do the following SQL:

INSERT INTO transactions (transaction_code) VALUES (NULL);

What this does is create a new row on the Transactions table, with transaction_code as NULL, instead of calculating the nextval of the sequence and inserting it on the corresponding column. Thus, as I found out, if you specify NULL to postgres, it assumes you really want to insert NULL into that column, regardless of it having a default value (I'm coming from ORACLE which has a different behavior).

I'm open to any solution on this, either if it is done on the database or on RoR:

  • either there is a way to exclude attributes from ActiveRecord's
    save
  • or there is a way to change a column's value before insert with a trigger
  • or there is a way to generate these sequence numbers within RoR
  • or any other way, as long as it works :-)

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

山田美奈子 2024-12-17 14:55:28

目前,您可能会陷入在 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 中看到这一点......但它确实做到了诡计。

For the moment, you might be stuck fetching and assigning the sequence in your ROR model like this:

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

I'm not particularily fond of this solution, since I'd like to see this corrected in AR directly... but it does do the trick.

梦与时光遇 2024-12-17 14:55:28

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

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 序列

If you want to insert the default value in to a column in an INSERT statement, you can use the keyword DEFAULT - no quotes:

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

Or you could spell out the default, nextval(...) in your case. See the manual here.


A trigger for that case is simple. That's actually what I would recommend if you want to make sure that only numbers from your sequence are entered, no matter what.

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

On a side note:
If you want to assign your own (non-sequential) numbers as 'sequence', I have written a solution for that in an answer a couple of days ago:
How to specify list of values for a postgresql sequence

鲜血染红嫁衣 2024-12-17 14:55:28

我在使用 Rails7 时仍然遇到这个问题 - 我可以看到 Rails 在插入中生成 NULL,但是将列从 integer 更改为 bigint 解决了这个问题。 - 然后 Rails 不会为我的排序列提供值,并且使用 DEFAULT nextval('number_seq')

I was still experiencing this issue with Rails7 - I could see that Rails was generating a NULL in the insert, but changing the column from integer to bigint solved it. - Rails then does not supply a value for my sequenced column and the DEFAULT nextval('number_seq') is used.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文