8

假設我有一個名爲Transaction的模型,它具有:transaction_code屬性。 我希望該屬性自動填入可能與id不同的序號(例如id=1的交易可能有transaction_code=1000)。Ruby on Rails + PostgreSQL:自定義序列的使用

我試圖在postgres上創建一個序列,然後使該序列的transaction_code列的默認值爲nextval。 的事情是,如果我不上RoR的任何值賦給@transaction.transaction_code,當我發出的回報率一個@transaction.save,它會嘗試做以下SQL:

INSERT INTO transactions (transaction_code) VALUES (NULL);

這樣做的是創建一個新的行在Transactions表上,將transaction_code設置爲NULL,而不是計算序列的nextval並將其插入相應的列。因此,正如我發現的那樣,如果你爲postgres指定NULL,它會假設你真的想將NULL插入到該列中,而不管它是否有默認值(我來自具有不同行爲的ORACLE)。

我接受這個任何解決方案,無論是如果對數據庫或回報率進行:

  • 要麼沒有排除從ActiveRecord的的 save
  • 或有屬性的方式插入前一種方法來改變列的值與觸發
  • 還是有辦法內的回報率
  • 或任何其他方式產生這些序列號,只要它的作品:-)

在此先感謝。

回答

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

+1

感謝Erwin的回答。問題是,在ActiveRecord的save方法中,你不能在INSERT中「發送」關鍵字DEFAULT(這可以解決這個問題,是的)。我更喜歡一種可以在Ruby on Rails應用程序中完全編碼的解決方案,而不是在數據庫上進行編程,這將使我無法在需要時無縫遷移到另一個DBMS。 –

+1

@Ricardo:「無縫遷移到另一個數據庫管理系統」是一個不錯的幻想,但它與現實沒有太大關係,對不起。一個觸發器的一個大缺點是,你將無法在Heroku共享數據庫上使用它。 –

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 

我不喜歡particularily這個解決方案,因爲我想看看這個科爾直接在AR中進行......但它的確有用。

相關問題