You might laugh when you here this, by there is an aggregate clause that triggers summary between breaks in values. The aggregrate clause is WITH ROLLUP
. (Look in MySQL Documentation under GROUP BY Modifiers)
let's take your query and make the following changes
- Remove
ORDER BY
- Substitute
WITH ROLLUP
- Remove
name
You get this
SELECT
cdr.datefield AS 'date',
a.id AS 'id',
SUM(t.debit_amount - t.credit_amount) AS 'balance'
FROM calendar cdr
JOIN transactions t ON (cdr.datefield >= t.value_date)
JOIN accounts a ON (a.id = t.account_id)
WHERE cdr.datefield IN ('2014-03-31', '2013-03-31', '2012-03-31')
GROUP BY cdr.datefield, a.id
WITH ROLLUP;
Here is what should happen
- In between each datefield, there will be
- datefield
id
NULL
- a sum of balance for that date
- The last row return
- datefield NULL
- id NULL
- a sum of balance for all dates
Based on the desired output, you want Cash
, Payables
and Issued Capital
as zero in case there is no transaction type for the given date. You also done want the last row because you don't want the grand total. What you do is take the new query, make it a subquery, and LEFT JOIN the accounts table to the subquery, returning zero for balance if it is NULL and exclude any row whose date is NULL.
Here is the new query
SELECT
BB.date,AA.id,AA.name,IFNULL(BB.balance,0) balance
FROM accounts AA LEFT JOIN
(SELECT
cdr.datefield AS 'date',
a.id AS 'id',
SUM(t.debit_amount - t.credit_amount) AS 'balance'
FROM calendar cdr
JOIN transactions t ON (cdr.datefield >= t.value_date)
JOIN accounts a ON (a.id = t.account_id)
WHERE cdr.datefield IN ('2014-03-31', '2013-03-31', '2012-03-31')
GROUP BY cdr.datefield, a.id
WITH ROLLUP) BB USING (id) WHERE AA.date IS NOT NULL
ORDER BY BB.date DESC,AA.id;
I have used WITH ROLLUP
to answer many posts in the DBA StackExchange
Give it a Try !!!
OBSERVATION #1
The MySQL Documentation gives you the Restrictions on Views
- It is not possible to create an index on a view.
- Indexes can be used for views processed using the merge algorithm. However, a view that is processed with the temptable algorithm is unable to take advantage of indexes on its underlying tables (although indexes can be used during generation of the temporary tables).
Subqueries cannot be used in the FROM clause of a view.
Therefore
- The result set of a View would be some temp table used for row-by-row retrieval
- There is no existing mechanism to index the result set coming from a view
Creating indexes only help the underlying base tables within the JOIN a the View, not the View itself.
OBSERVATION #2
You mentioned this
Some suggest to do aggregation in subquery before join which is not possible as MySQL doesn't allow subquery in FROM clause.
That's not true. I have a post in StackOverflow (Fetching a Single Row from Join Table) that clearly demonstrates doing an aggregation in a subquery followed by all kinds of JOINs to that subquery.
Best Answer
Scalar subqueries that return no rows have a return "value" of
NULL
... so all you need to do is coerce thatNULL
to a 0 directly outside the subquery withIFNULL()
: