Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / SQL

Use Of Self Joins Instead Of Cursor Or While Loop

4.15/5 (8 votes)
5 Nov 2014CPOL2 min read 24.4K   58  
Retrieving Running balance in easy steps and less time

Introduction

This is an example and I like using it every time I have such a requirement, i.e., to get the total of amount as you read the next record by moving up or down.

This example explains how you could get the running balance for an account using self joins.

Background

Earlier and even now, many people use the Cursor and while loop to get the balance of an account by date and their transaction.

Cursor, as we all know, takes time to execute and a cumbersome code syntax.

Which was eventually replaced by while loop, though it was a performance improvement as against cursor it has to go to each record and do the operation.

So here, we are going to see the examples of each and self join.

Using the Code

Consider you have the table "Passbook" as below:

Image 1

So to get the account balance by each transaction, we can use Cursor:

SQL
DECLARE @BalCursor float=0
DECLARE @TransctionNumber int
DECLARE @TransactionType Varchar(1)
DECLARE @TransactionAmount float

DECLARE @MyCursor CURSOR

SET @MyCursor = CURSOR 
FOR
SELECT TransctionNumber,TransactionType,TransactionAmount
FROM   #Passbook order by TransctionNumber

OPEN @MyCursor
    FETCH NEXT FROM @MyCursor
    INTO @TransctionNumber, @TransactionType, @TransactionAmount
        WHILE @@FETCH_STATUS = 0
        BEGIN
            select @BalCursor=@BalCursor+Case when @TransactionType='C' 
                       then @TransactionAmount else -@TransactionAmount end
            

            Update #Passbook set AccountBalance=@BalCursor 
                         where TransctionNumber=@TransctionNumber
             
            FETCH NEXT FROM @MyCursor
            INTO @TransctionNumber, @TransactionType, @TransactionAmount
        END
CLOSE @MyCursor
DEALLOCATE @MyCursor

select * from #Passbook

You will get output as shown below:

Image 2

Now, you can do the same thing using While loop as below:

SQL
Update #Passbook set AccountBalance=0 

DECLARE @WhileBalance float
Declare @MinTransNo int,@MaxTransNo int
select @MinTransNo=MIN(TransctionNumber),@MaxTransNo=MAX(TransctionNumber) from #Passbook

While @MinTransNo<=@MaxTransNo
BEGIN

            select @WhileBalance=SUM(Case when p1.TransactionType='C' _
            then P1.TransactionAmount else -P1.TransactionAmount end)
            From #Passbook p1 where TransctionNumber<=@MinTransNo

            Update #Passbook set AccountBalance=@WhileBalance where TransctionNumber=@MinTransNo
            
            set @MinTransNo=@MinTransNo+1

END

select * from #Passbook

and here comes the Self Join :)

SQL
select
P2.TransctionNumber,P2.AccountHolderCode,P2.TransactionType,P2.TransactionDate,_
SUM(Case when p1.TransactionType='C' _
then P1.TransactionAmount else -P1.TransactionAmount end) AccountBalance from #Passbook P1
Inner Join 
#Passbook P2
On P1.AccountHolderCode=P2.AccountHolderCode and P1.TransctionNumber<=P2.TransctionNumber
Group By P2.TransctionNumber,P2.AccountHolderCode,P2.TransactionType,P2.TransactionDate

which can achieve the same output.

Also some cool stuff with below query and output as below:

Image 3

I have attached the script to create the table with all the queries as described here. Anyone interested can use that and play around with it.

New addition to the above script is the new feature of 2012 SQL version which is Over clause and the code for that is as below:

SQL
SELECT 
         TransactionDate,AccountHolderCode, TransctionNumber,
         AccountBalance=SUM(Case when p2.TransactionType='C' 
                            then P2.TransactionAmount else -P2.TransactionAmount end)
                 OVER (ORDER BY p2.TransctionNumber)
FROM  #Passbook p2
ORDER BY TransactionDate,AccountHolderCode,TransctionNumber;

which will result in the same output of running balances.

And now, I also have comparison of all the above queries with execution plan and the surprising result is that the Self join has the execution cost less than all.

And here that goes:

Image 4

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)