patternsqlModerate
Calculate row value based on previous and actual row values
Viewed 0 times
previousvaluesactualvaluecalculatebasedandrow
Problem
Hi everyone and thanks for your help.
I have the following situation: a table called statements that contains fields id(int), stmnt_date(date), debit(double), credit(double) and balance(double)
I want to calculate the balance following these rules:
The first row balance (chronologically) = debit - credit and for the rest of the rows
current row balance = chronologically previous row balance + current row debit - current row credit
As you can see on the picture above the rows are not arranged by date and that's why I used the word chronologically twice to emphasize on the importance of the stmnt_date value.
Thank you very much for your help.
I have the following situation: a table called statements that contains fields id(int), stmnt_date(date), debit(double), credit(double) and balance(double)
I want to calculate the balance following these rules:
The first row balance (chronologically) = debit - credit and for the rest of the rows
current row balance = chronologically previous row balance + current row debit - current row credit
As you can see on the picture above the rows are not arranged by date and that's why I used the word chronologically twice to emphasize on the importance of the stmnt_date value.
Thank you very much for your help.
Solution
Assuming that
Unfortunately, MySQL does not (yet) have implemented analytic functions. You can solve the problem either with strict SQL, by self-joining the table (which should be rather inefficient although working 100%) or by using a specific MySQL feature, variables (which would be quite efficient but you'd have to test it when upgrading mysql, to be sure that the results are still correct and not mangled by some optimization improvement):
With your data, it will result in:
stmnt_date has a UNIQUE constraint, this would be fairly easy with window/analytic functions:SELECT
s.stmnt_date, s.debit, s.credit,
SUM(s.debit - s.credit) OVER (ORDER BY s.stmnt_date
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
AS balance
FROM
statements AS s
ORDER BY
stmnt_date ;Unfortunately, MySQL does not (yet) have implemented analytic functions. You can solve the problem either with strict SQL, by self-joining the table (which should be rather inefficient although working 100%) or by using a specific MySQL feature, variables (which would be quite efficient but you'd have to test it when upgrading mysql, to be sure that the results are still correct and not mangled by some optimization improvement):
SELECT
s.stmnt_date, s.debit, s.credit,
@b := @b + s.debit - s.credit AS balance
FROM
(SELECT @b := 0.0) AS dummy
CROSS JOIN
statements AS s
ORDER BY
stmnt_date ;With your data, it will result in:
+------------+-------+--------+---------+
| stmnt_date | debit | credit | balance |
+------------+-------+--------+---------+
| 2014-05-15 | 3000 | 0 | 3000 |
| 2014-06-17 | 20000 | 0 | 23000 |
| 2014-07-16 | 0 | 3000 | 20000 |
| 2014-08-14 | 0 | 3000 | 17000 |
| 2015-02-01 | 3000 | 0 | 20000 |
+------------+-------+--------+---------+
5 rows in set (0.00 sec)Code Snippets
SELECT
s.stmnt_date, s.debit, s.credit,
SUM(s.debit - s.credit) OVER (ORDER BY s.stmnt_date
ROWS BETWEEN UNBOUNDED PRECEDING
AND CURRENT ROW)
AS balance
FROM
statements AS s
ORDER BY
stmnt_date ;SELECT
s.stmnt_date, s.debit, s.credit,
@b := @b + s.debit - s.credit AS balance
FROM
(SELECT @b := 0.0) AS dummy
CROSS JOIN
statements AS s
ORDER BY
stmnt_date ;+------------+-------+--------+---------+
| stmnt_date | debit | credit | balance |
+------------+-------+--------+---------+
| 2014-05-15 | 3000 | 0 | 3000 |
| 2014-06-17 | 20000 | 0 | 23000 |
| 2014-07-16 | 0 | 3000 | 20000 |
| 2014-08-14 | 0 | 3000 | 17000 |
| 2015-02-01 | 3000 | 0 | 20000 |
+------------+-------+--------+---------+
5 rows in set (0.00 sec)Context
StackExchange Database Administrators Q#94545, answer score: 14
Revisions (0)
No revisions yet.