2013-12-15 17 views
0

在我Invoice模型我試圖獲取所有未付發票:如何在函數而不是數據庫列上運行where子句?

class Invoice < ActiveRecord::Base 

    has_many :payments 

    def self.outstanding 
    where("outstanding_amount != 0") 
    end 

    private 

    def outstanding_amount 
    total - payments.to_a.sum(&:amount_in_cents) 
    end 

end 

這不起作用,但是,因爲我沒有一個數據庫列outstanding_amount。有沒有辦法在函數而不是數據庫字段上運行where子句?

感謝您的任何幫助。

+0

您可以將搜索條件作爲參數傳遞並讓方法處理它。但在你的情況,如果你只是把它放在: 'def self.outstanding outstanding_amount == 0? ?無:outstanding_amount 結束' –

回答

3

您需要將表達式作爲having子句的一部分傳遞。我會推遲到RoR的嚮導,活動記錄語法,但你最終查詢應達到這樣的:如果大部分行不平衡(不太可能)

select ... 
from ... join payments on ... 
where ... 
group by ... 
having total != sum(payments.amount) 

,另一種可能是相關子查詢:

select ... 
from ... 
where ... 
and total != (select sum(amount) from payment where ...) 

(不要做上面如果大多數行是不平衡的,因爲性能會吸。)

一個最後的選擇(這其實我建議)是維持paid列 - 理想情況下,雖然不必然,使用觸發器。然後,您可以使用:

select ... 
from ... 
where ... 
and total != paid 

更重要的是,你可以改寫後者,如:

where total - paid != 0 

,然後添加一個部分索引上(total - paid) where (total - paid != 0),以獲得最佳性能。

+0

感謝您的好寫。事實上,我現在在我的發票表中使用了「收費」列(實際上在我的例子中它被稱爲「outstanding_amount」)。我希望有一天能夠撤消該專欄,因爲正如您指出的那樣,每當保存新的發票或付款記錄時都需要*維護*。但是你讓我相信,保留這個專欄可能會更好。看來真的沒有其他辦法可以做到了。 – Tintin81

+0

你是對的,但你應該花更多時間在你的答案上,並添加完整的SQL查詢(不包括「...」)。 +1 – SergeyKutsko

+1

@SergeyKutsko:同意,但OP沒有提供架構。 :-) –

相關問題