samedi 25 avril 2015

ActiveRecord complex calculation - how to solve it the rails way?


Currently I'm trying to figure out how to do a calculation the proper and best way using Rails 4.1.

(Simplified example)

Movement (ActiveRecord Model)

id: integer
paid_at: datetime
value: decimal
debit_account_id: references
credit_account_id: references
category_id: references
...

The Goal

I want a four column list as result, having:

  1. The paid_at date (grouped by)
  2. The sum of all values for the paid_at date, IF condition ONE is true
  3. The sum of all values for the paid_at date, IF condition TWO is true
  4. The difference of both values (Column 2 minus Column 3)

Conditions may be different, an easy case would be:

  • Condition 1: debit_account_id IN (3, 4)
  • Condition 2: credit_account_id IN (3, 4)
  • Just another one: Any field of a joined account must have a field match a value
  • ...

Example result

 date       | earnings | spendings |  total |
 -----------+----------+-----------+--------+
 2015-01-01 |   120.00 |     50.00 |  70.00 |
 2015-01-05 |     0.00 |     10.00 | -10.00 |
 2015-01-06 |   100.00 |      0.00 | 100.00 |
 ...

One possible (ugly) SQL way

SELECT
  DATE(`paid_at`) AS `date`,
  SUM(IF(credit_account_id IN(:credit_accounts), value, 0)) AS `earnings`,
  SUM(IF(debit_account_id IN(:debit_accounts), value, 0)) AS `spendings`,
  SUM(IF(credit_account_id IN(:credit_accounts), value, 0)) - SUM(IF(debit_account_id IN(:debit_accounts), value, 0)) AS `total`
FROM 
  movements
WHERE
  credit_account_id IN (:credit_accounts)
OR
  debit_account_id IN (:debit_accounts)
GROUP BY `date`
ORDER BY `date`;

The question

How can I get the expected result in a better way? And how to do it using Rails?

~~ Thank you in advance for any help! :D ~~


Aucun commentaire:

Enregistrer un commentaire