代码之家  ›  专栏  ›  技术社区  ›  Daniel Abrahamsson

如何有效地求和

  •  0
  • Daniel Abrahamsson  · 技术社区  · 16 年前

    在我开始之前,我为一个糟糕的标题道歉,但我不能想出一个令人满意的方式来描述我的问题。如果你能想出一个更好的标题,我会很乐意改变的。

    假设我有一个 Account 模型与A Transaction 模型,我想实现 Account#days_since_balance_was_atleast 方法,以和为唯一参数。做这件事的有效方法是什么?

    下面是一些示例代码:

    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
    

    那么,你如何解决这个问题呢?

    4 回复  |  直到 16 年前
        1
  •  1
  •   Mladen Jablanović    16 年前

    不应该那么难,使用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
  •  1
  •   John La Rooy    16 年前

    考虑将平衡作为一个单独的字段。然后,您的问题从一个困难的求和问题转移到一个简单地保持平衡字段与事务一致的问题上。

        3
  •  0
  •   Bobby B    16 年前

    丹尼尔,

    这相当棘手。总和必须是动态的吗(我假设是动态的)。如果没有,您可以捕获达到阈值的日期,并将其用于一些简单的日期逻辑。

    不过,假设您必须进行动态处理,那么我将加载整个事务集合,并反向遍历它,跟踪总和,直到您打破阈值。我在数据库世界中比在应用程序开发中更舒服,我不知道在数据库层中,如果不使用特定于特定DBE的语法,您将如何解决这一问题——这意味着您可能不希望通过ActiveRecord来完成这项工作。

    祝你好运-难题!

    BB

        4
  •  0
  •   Daniel Abrahamsson    16 年前

    我设法将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
    

    我会接受迈拉登的答案,用一个指向这个的指针,因为正是这个指针导致了结果,除非有人想出了一个更聪明的方法。我不确定这是否是最好的方法,但它避免了实例化许多ActiveRecord对象的繁重工作,并且让DB完成了艰巨的工作。