I have the following query:
SELECT
SUM("balance_transactions"."fee") AS sum_id
FROM "balance_transactions"
JOIN charges ON balance_transactions.source = charges.balance_id
WHERE "balance_transactions"."account_id" = 6
AND (balance_transactions.type = 'charge'
AND charges.refunded = false
AND charges.invoice IS NOT NULL)
AND ("balance_transactions"."created" BETWEEN '2013-12-20' AND '2014-01-19');
What that does is adds up all the "fees" that occurred between those two dates. Great. Works fine.
The problem is that I almost always need those fees for hundreds of date ranges at a time, which amounts to me running that same query hundreds of times. Not efficient.
But is there some way to condense this into a single query for all the date ranges?
For instance, I'd be calling SUM
for a series of ranges like this:
2013-12-20 to 2014-01-19
2013-12-21 to 2014-01-20
2013-12-22 to 2014-01-21
2013-12-23 to 2014-01-22
2013-12-24 to 2014-01-23
...so on and so on
I need to output the sum of fees collected in each date range (and ultimately need that in an array).
So, any ideas on a way to handle that and reduce database transactions?
FWIW, this is on Postgres inside a Rails app.
If you need to add a group of numbers in your table you can use the SUM function in SQL. This is the basic syntax: SELECT SUM(column_name) FROM table_name; The SELECT statement in SQL tells the computer to get data from the table.
SQL SUM() with where clause We can selectively find the sum of only those rows, which satisfy the given condition. To do this, we can use the where clause in the SQL statement.
Assuming I understand your request correctly I think what you need is something along these lines:
SELECT "periods"."start_date",
"periods"."end_date",
SUM(CASE WHEN "balance_transactions"."created" BETWEEN "periods"."start_date" AND "periods"."end_date" THEN "balance_transactions"."fee" ELSE 0.00 END) AS period_sum
FROM "balance_transactions"
JOIN charges ON balance_transactions.source = charges.balance_id
JOIN ( SELECT '2013-12-20'::date as start_date, '2014-01-19'::date as end_date UNION ALL
SELECT '2013-12-21'::date as start_date, '2014-01-20'::date as end_date UNION ALL
SELECT '2013-12-22'::date as start_date, '2014-01-21'::date as end_date UNION ALL
SELECT '2013-12-23'::date as start_date, '2014-01-22'::date as end_date UNION ALL
SELECT '2013-12-24'::date as start_date, '2014-01-23'::date as end_date
) as periods
ON "balance_transactions"."created" BETWEEN "periods"."start_date" AND "periods"."end_date"
WHERE "balance_transactions"."account_id" = 6
AND "balance_transactions"."type" = 'charge'
AND "charges"."refunded" = false
AND "charges"."invoice" IS NOT NULL
GROUP BY "periods"."start_date", "periods"."end_date"
This should return you all the periods you're interested in in one single resultset. Since the query is 'generated' on the fly in your front-end you can add as many rows to the periods part as you want.
Edit: with some trial and error I managed to get it working [in sqlFiddle][1] and updated the syntax above accordingly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With