Как эффективно сложить - PullRequest
0 голосов
/ 20 июля 2010

Прежде чем начать, я прошу прощения за плохой заголовок, но я не смог придумать тот, который удовлетворительно описывает мой вопрос.Если вы придумаете лучший заголовок, я с удовольствием переключусь.

Предположим, у меня есть модель Account и модель 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 ]

1 голос
/ 20 июля 2010

Рассмотрите вопрос о сохранении баланса в качестве отдельного поля.Тогда ваша задача переходит от сложной задачи суммирования к простому поддержанию поля баланса в соответствии с транзакциями

1 голос
/ 20 июля 2010

Не должно быть так сложно, используя 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, либо создайте представление в вашей базе данных.

0 голосов
/ 21 июля 2010

Мне удалось изменить код Младенса в этот рабочий фрагмент:

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 и позволяет БД выполнять тяжелую работу.

0 голосов
/ 20 июля 2010

Даниэль,

Это довольно сложно.Должна ли сумма быть динамической (я так полагаю).Если нет, вы могли бы зафиксировать дату достижения порога и использовать ее для некоторой простой логики дат.

Если предположить, что вам нужно работать динамически, я бы загрузил всю коллекцию транзакций и повторил бы ее в обратном порядкеотслеживать сумму, пока вы не нарушите свой порог.Я чувствую себя более комфортно в мире баз данных, чем в разработке приложений, и я не уверен, как бы вы решили это на уровне db без использования синтаксиса, специфичного для конкретного dbe - что означает, что это, вероятно, не то, что вы бы сделалихочу сделать через ActiveRecord.

Удачи - трудная проблема!

BB

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...