【问题标题】:Ruby on Rails+PostgreSQL: usage of custom sequencesRuby on Rails+PostgreSQL:自定义序列的使用
【发布时间】: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 中生成这些序列号
  • 或任何其他方式,只要它有效:-)

提前致谢。

【问题讨论】:

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


    【解决方案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 共享数据库上使用它。
    猜你喜欢
    • 1970-01-01
    • 2014-07-27
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-05
    • 2012-09-01
    相关资源
    最近更新 更多