在我开始之前,我为一个糟糕的标题道歉,但我无法想出一个以令人满意的方式描述我的问题的标题。如果你想出一个更好的头衔,我很乐意转换。
假设我有一个Account
模型和一个Transaction
模型,我想实现一个Account#days_since_balance_was_atleast
方法,将sum作为唯一参数。什么是有效的方法呢?
以下是一些示例代码:
class Transaction < ActiveRecord::Base
validates_presence_of :account_id, :created_at, :amount
belongs_to :account
# Some logic to update account balance at creation...
end
class Account < ActiveRecord::Base
validates_presence_of :balance
has_many :transactions
def days_since_balance_was_atleast(sum)
#How should I implement this?
end
end
我应该使用一些智能SQL片段,还是ActiveRecord :: Calculations?加载所有交易并手动倒退似乎是一个非常糟糕的主意(特别是因为可能有很多交易)。如果我坚持最后一种方法,你认为批量检索交易是否明智。
它应该生成什么(更新):
# We have the following transactions
# (time is unimportant for the result unless it is 00.00)
# Days ago 0 1 2 3 4 5 6 7
# Amount -20 10 -60 -30 50 50 -100 100
account.balance == 0 # true
days_since_balance_was(100) == 3 # true
那么,你会如何解决这个问题?
答案 0 :(得分:1)
考虑将余额保持为单独的字段。然后你的问题从困难的求和问题转变为简单地保持余额字段与交易一致
答案 1 :(得分:1)
使用SQL连接不应该那么难。有点像:
SELECT t1.time
FROM transactions t1
LEFT JOIN transactions t2 ON t2.time < t1.time
HAVING SUM(t2.amount) >= 100
GROUP BY t1.id, t1.time
ORDER BY t1.time
LIMIT 1
使用AR实现它,或在数据库中创建视图。
答案 2 :(得分:0)
丹尼尔,
这很棘手。总和是否必须是动态的(我假设是这样)。如果没有,您可以捕获达到阈值的日期,并将其用于某个简单的日期逻辑。
假设你必须动态,我会加载整个事务集合并反过来跟踪总和,直到你打破你的门槛。我在数据库世界中比在应用程序开发中更舒服,而且我不确定如何在不使用特定dbe特定语法的情况下在db层中解决这个问题 - 这意味着它可能不是你想要的想通过ActiveRecord做。
祝你好运 - 难题!
BB
答案 3 :(得分:0)
我设法将Mladens代码更改为此工作代码段:
SELECT t1.time
FROM transactions t1
LEFT JOIN transactions t2 ON t2.time >= t1.time
WHERE t1.account_id=9 AND t2.account_id=9
GROUP BY t1.id, t1.time
HAVING SUM(-t2.amount) >= 100
ORDER BY t1.time DESC
LIMIT 1
我会接受Mladen的答案,指向这个,因为它是导致结果的那个,除非有人想出一个更聪明的方法。我不确定这是否是最好的方法,但是它避免了实例化大量ActiveRecord对象的繁重工作,并让DB完成了艰苦的工作。