Click here to Skip to main content
15,885,546 members
Articles / Programming Languages / SQL
Tip/Trick

Use Of Self Joins Instead Of Cursor Or While Loop

Rate me:
Please Sign up or sign in to vote.
4.15/5 (8 votes)
5 Nov 2014CPOL2 min read 23.7K   58   11   7
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)


Written By
Software Developer
India India
I am a working professional and , I am here to learn and share the knowledge about technologies.

Comments and Discussions

 
GeneralMy vote of 2 Pin
Tomas Takac6-Nov-14 4:17
Tomas Takac6-Nov-14 4:17 
GeneralRe: My vote of 2 Pin
Shweta N Mishra6-Nov-14 4:38
professionalShweta N Mishra6-Nov-14 4:38 
Thanks any feedback for improvement to the article is welcome Smile | :)

Will make necessary changes for updates from 2012.

Refer article is good,but one point about using the subquery is that , it may be an option/Way to get the solution but its not a good option. Conditions can be handled in joins also.
SuggestionA number of problems Pin
scottb15-Nov-14 22:35
scottb15-Nov-14 22:35 
GeneralRe: A number of problems Pin
Shweta N Mishra6-Nov-14 0:46
professionalShweta N Mishra6-Nov-14 0:46 
GeneralRe: A number of problems Pin
Shweta N Mishra6-Nov-14 5:38
professionalShweta N Mishra6-Nov-14 5:38 
QuestionBroken Links Pin
pakawaller5-Nov-14 9:14
pakawaller5-Nov-14 9:14 
AnswerRe: Broken Links Pin
Shweta N Mishra6-Nov-14 1:09
professionalShweta N Mishra6-Nov-14 1:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.