How to do calculations based on a running total with MSSQL
The problem is: Once you have a running balance, how do you do other calculations based on the running balance.
The answer is: Common Table Expression or CTE.
Starting with SQL Server 2005, Microsoft has implemented the Common Table Expression or CTE which is an ANSI SQL-99 standard. It's also implemented by Oracle and IBM DB2.
Common Table Expression
- It's a temporary result set.
- It only exists for the duration of the query.
- Can be applied to:
- SELECT
- INSERT
- UPDATE
- DELETE
- CREATE VIEW
Common Table Expression are used for:
- Recursive queries.
- Substitute views.
- Grouping by a column derived from a sub-query.
- Use the resulting table many times in the same statement.
Translation: we can use use the common table expression to make calculations based on other calculations or summary operations.
Data used
emp_short AS 'Employee',
trans_date AS 'Date',
trans_type AS 'Transaction',
amount AS 'Amount'
FROM transactions;
go
Counter Employee Date Transaction Amount ----------- ---------- ----------------------- ----------- --------------------- 1 000010 2007-05-01 00:00:00 IN 345.00 11 000010 2007-05-02 00:00:00 IN 175.00 21 000010 2007-05-03 00:00:00 OUT -75.00 31 000010 2007-05-05 00:00:00 OUT -100.00 41 000030 2007-05-15 00:00:00 IN 10000.00 51 000030 2007-05-16 00:00:00 IN 435.00 61 000030 2007-05-20 00:00:00 OUT -125.00 71 000030 2007-05-30 00:00:00 OUT -1100.00 81 000110 2007-04-12 00:00:00 OUT -250.00 91 000110 2007-04-30 00:00:00 OUT -75.00 101 000110 2007-05-10 00:00:00 IN 1000.00 111 000190 2007-06-01 00:00:00 IN 99.00 121 000190 2007-06-01 00:00:00 IN 134.00 131 000310 2007-07-01 00:00:00 IN 1156.40 141 000310 2007-07-02 00:00:00 IN 67.00 151 000310 2007-08-01 00:00:00 OUT -586.00 (16 row(s) affected)
Using the Common Table Expression in MSSQL
(
SELECT a.counter ,
a.emp_short ,
a.trans_date ,
CASE WHEN a.trans_type = 'IN' THEN 'Deposit' ELSE 'Withdrawl' END,
CASE WHEN a.trans_type = 'IN' THEN a.amount ELSE -a.amount END,
' ',
(SELECT SUM(b.amount)
FROM transactions AS b
WHERE b.counter <= a.counter and
b.emp_short = a.emp_short)
FROM transactions AS a
)
SELECT num AS 'Entry',
emp AS 'Employee',
tdate AS 'Date',
trans AS 'Transaction',
amt AS 'Amount',
bal AS 'Balance',
CASE WHEN bal < 0 THEN 'Overdraft' ELSE ' ' END AS 'Overdraft'
FROM bstatement
ORDER BY emp, tdate, num;
go
The format of the Common Table Expression is very simple:
- The Common Table Expression name just after the WITH keyword.
- The column list which is optional.
- The query within parentheses after the AS keyword.
- The calculations are done on the outside query.
Entry Employee Date Transaction Amount Balance Overdraft ----------- ---------- ----------------------- ----------- --------------------- --------------------- --------- 1 000010 2007-05-01 00:00:00 Deposit 345.00 345.00 11 000010 2007-05-02 00:00:00 Deposit 175.00 520.00 21 000010 2007-05-03 00:00:00 Withdrawl 75.00 445.00 31 000010 2007-05-05 00:00:00 Withdrawl 100.00 345.00 41 000030 2007-05-15 00:00:00 Deposit 10000.00 10000.00 51 000030 2007-05-16 00:00:00 Deposit 435.00 10435.00 61 000030 2007-05-20 00:00:00 Withdrawl 125.00 10310.00 71 000030 2007-05-30 00:00:00 Withdrawl 1100.00 9210.00 81 000110 2007-04-12 00:00:00 Withdrawl 250.00 -250.00 Overdraft 91 000110 2007-04-30 00:00:00 Withdrawl 75.00 -325.00 Overdraft 101 000110 2007-05-10 00:00:00 Deposit 1000.00 675.00 111 000190 2007-06-01 00:00:00 Deposit 99.00 99.00 121 000190 2007-06-01 00:00:00 Deposit 134.00 233.00 131 000310 2007-07-01 00:00:00 Deposit 1156.40 1156.40 141 000310 2007-07-02 00:00:00 Deposit 67.00 1223.40 151 000310 2007-08-01 00:00:00 Withdrawl 586.00 637.40 (16 row(s) affected)
- The query using the Common Table Expression must be the first query appearing after the definition of the Common Table Expression.
- The Common Table Expression only exists for the duration of that one single query. It cannot be reused as a temporary table can be.

