SIGN UP MEMBER LOGIN:    
ARTICLE

Cursors and Alternative to the Cursors in Sql server

Posted by Senthilkumar Articles | Databases & DBA September 01, 2009
This article explains about simple cursor and alternative method to the cursor.
Reader Level:
 

Introduction:

The cursor is one of the important elements in the sql server. As you know it will do the row by row operation. It will affect the performance of the sql server. Because it will use lot of IO to do the operations. The web application performance not only depends on the application. We have to consider the database also. Because when we want to display the records from the database then it must be effectively do the backend processing. Let us see with an example.

 

Cursors in Sql Server:

The cursors will be used when we want to perform the looping of the table result set. In the sql server we don't have any inbuilt functions to do the looping of the Table results like Array in the any programming language. If you want to iterate the table based on the key then we cannot say it will be in the sequence order.

 

Consider an example; I want to perform the product sales report for every product in the Product Master table. If the product key is an integer then we don't have any problem in such cases. If it is non integer then definitely we cannot iterate.

 

Suppose if you have 10 products in the product table in the order of Product ID is 1,2,3,4,5,6,7,8,9,10. Then we don't have any problem. But two products has deleted then now its order like 1,3,5,6,7,8,9,10. Then there is something needs to perform cursor. Just I take Product table is an example to catch easily.

 

The cursor what it does, it will be stored as a object in the memory then it has the inbuilt row cursor then it will do one by one. Then it will allocate some memory space in the sql server memory, it must be deallocated and closed its references in the memory.

 

USE [Northwind]

GO

 

IF OBJECT_ID('Pr_ProductSalesReport','p') IS NOT NULL

BEGIN

   DROP PROCEDURE Pr_ProductSalesReport

   PRINT '<< Pr_ProductSalesReport procedure dropped >>'

END

GO

 

CREATE PROCEDURE Pr_ProductSalesReport

AS

BEGIN

/*

  Purpose: Calculate the total quantity and sales of the product in 

           product wise.

  Input  : No input specified. It will calculate for all the products

           in Product Master table.

  Output : ProductID,ProductName,Total Quantity and Grand Total of 

           sale.

  Method : The report generated using the Cursor

 

-----------------------------------------------------------------------

*********************** Modification History **************************

-----------------------------------------------------------------------

S.No             Name              Date                   Version

-----------------------------------------------------------------------

1.        Erode Senthilkumar     Sep 01, 2009               1.0

-----------------------------------------------------------------------

*/

    SET NOCOUNT ON

    SET XACT_ABORT ON

 

    DECLARE ProductCursor CURSOR FOR

       SELECT ProductID FROM Products

    DECLARE @ProductID INT

    DECLARE @ProductName VARCHAR(100)

    DECLARE @TotalQty INT

    DECLARE @Total MONEY

   

    DECLARE @ProductSales TABLE

    (

        iSNo INT IDENTITY(1,1)

       ,iProductID INT

       ,vProductName VARCHAR(100)

       ,iTotalQty INT

       ,iGrandTotal MONEY

    )

 

    OPEN ProductCursor

  

    FETCH NEXT FROM ProductCursor INTO @ProductID

   

    WHILE @@FETCH_STATUS = 0

    BEGIN

       SELECT @ProductName = ProductName FROM Products

              WHERE ProductID = @ProductID

       SELECT @TotalQty = SUM(Quantity),@Total = SUM(UnitPrice*Quantity) FROM "Order Details"  

              WHERE ProductID = @ProductID

       INSERT INTO  @ProductSales(iProductID,vProductName,iTotalQty,iGrandTotal)

              VALUES(@ProductID,@ProductName,@TotalQty,@Total)

      

       FETCH NEXT FROM ProductCursor INTO @ProductID

    END

     CLOSE ProductCursor

     DEALLOCATE ProductCursor

  

     SELECT * FROM @ProductSales

END

GO

 

IF OBJECT_ID('Pr_ProductSalesReport','p') IS NOT NULL

BEGIN

   PRINT '<< Pr_ProductSalesReport procedure dropped >>'

END

GO

 

EXEC Pr_ProductSalesReport

GO

 

IF OBJECT_ID('Pr_ProductSalesAlternativeReport','p') IS NOT NULL

BEGIN

    DROP PROCEDURE Pr_ProductSalesAlternativeReport

    PRINT '<< Pr_ProductSalesAlternativeReport procedure dropped >>'

END

GO

 

CREATE PROCEDURE Pr_ProductSalesAlternativeReport

AS

BEGIN

/*

  Purpose: Calculate the total quantity and sales of the product in

           product wise.

  Input  : No input specified. It will calculate for all the products

           in Product Master table.

  Output : ProductID,ProductName,Total Quantity and Grand Total of

           sale.

  Method : The report generated without using the Cursor

 

-----------------------------------------------------------------------

*********************  Modification History   *************************

-----------------------------------------------------------------------

S.No             Name            Date                   Version

-----------------------------------------------------------------------

1.        Erode Senthilkumar   Sep 01, 2009              1.0

-----------------------------------------------------------------------

*/

    SET NOCOUNT ON

    SET XACT_ABORT ON

 

    DECLARE @ProductID INT

    DECLARE @ProductName VARCHAR(100)

    DECLARE @TotalQty INT

    DECLARE @Total MONEY

    DECLARE @Index INT

    DECLARE @RecordCnt INT

   

    DECLARE @ProdID TABLE(

     iSNo INT IDENTITY(1,1)

    ,iProductID INT

    )

    DECLARE @ProductSales TABLE

    (

        iSNo INT IDENTITY(1,1)

       ,iProductID INT

       ,vProductName VARCHAR(100)

       ,iTotalQty INT

       ,iGrandTotal MONEY

    )

   

    SELECT @Index = 1

 

    INSERT INTO @ProdID(iProductID)

    SELECT ProductID FROM Products ORDER BY ProductID ASC

   

    SELECT @RecordCnt = COUNT(iSNo) FROM @ProdID

   

    WHILE (@Index <= @RecordCnt)

    BEGIN

       SELECT @ProductID = iProductID FROM @ProdID WHERE iSNo = @Index

       SELECT @ProductName = ProductName FROM Products

              WHERE ProductID = @ProductID

       SELECT @TotalQty = SUM(Quantity),@Total = SUM(UnitPrice*Quantity) FROM "Order Details" WHERE ProductID = @ProductID

       INSERT INTO  @ProductSales(iProductID,vProductName,iTotalQty,iGrandTotal)

              VALUES(@ProductID,@ProductName,@TotalQty,@Total)

       SELECT @Index = @Index + 1

    END

     SELECT * FROM @ProductSales

END

GO

 

IF OBJECT_ID('Pr_ProductSalesAlternativeReport','p') IS NOT NULL

BEGIN

    PRINT '<< Pr_ProductSalesAlternativeReport procedure created >>'

END

GO

 

EXEC Pr_ProductSalesAlternativeReport

GO

The first procedure has implemented using the simple cursor. It will do row-by-row operation using the cursor. It will fetch the record from the cursor result. As we discussed it will take lot of IO reads and it utilizes lot of memory. It will affect the performance of the other query processing in the sql server.

 

The second procedure shows alternative way to implement the cursor. It will give the same result as like stored procedure 1. Here it's like ordinary sql statements using the table variable.

 

As I said when we need the cursor. If you cannot get order of sequence to process the table then we must need some thing like cursor to process row-by-row processing.

Just think we need order of sequence. For that we have created the table variable, what it does it has one identity column and key field which we are going to process the other functionalities.

 

Here consider the Product ID has like this.

1, 3,5,7,8,9,10

 

So definitely I cannot take the product id in the loop to process.

CREATE @ProdTable TABLE (

iSNo INT IDENTITY(1,1),

 ProductID INT

)

 

INSERT INTO @ProdTable(ProductID)

SELECT ProductID FROM Products

 

SELECT * FROM @ProdTable

 

iSNo

ProductID

1

1

2

3

3

5

4

7

5

8

6

9

7

10

 

Now we have the order of sequence in the table. Then we can perform the row by row operations using the looping statements in the sql server.

 

Here the entire product id will be inserted into the table variable. Here we have used the table variable. It will give the more performance. The same result can be achieved using the temp table. As you know the temp table will be stored in the TempDB database. It will work across the database. It will occupy the unnecessary spaces in the sql server memory. It must be deleted once the process gets over.

 

But the table variable is best when we are going to use limited records in the table. Because it will be there in processor memory. Once it cross the level of the data storage then it will move to the tempdb. This life time of the table is only up to that stored procedure.

 

Conclusion:

I hope that this above method will be very useful. I expect your valuable suggestions and corrections. I have attached this script exercise in this article.

Login to add your contents and source code to this article
share this article :
post comment
 

First, thank you for the article. It helps me a lot. However, I have the following four questions: Let's say I have a table PRODUCT created as: PRODUCT(Prod_Id, Prod_Name, Prod_Color, Prod_Qty) 1) Can a cursor pull more than one column (field) in a table, or does it have to be always one? For example, DECLARE ProdCursor FOR SELECT * FROM PRODUCT 2) If the answer to question 1 is yes, then how to access these fields from the cursor recordset? For example, how to read the name and color into @PName, @PColor? As an illustration, in MS Access the process is: @PName = recordset!Prod_Name @PColor = recordset!Prod_Color 3) How to update a value in the cursor recordset? As an illustration, in MS Access the process is: recordset.Edit recordset!Prod_Name = @PName recordset!Prod_Color = @PColor recordset.Update 4) Is there an alternative way to question 2 and 3 that does not use a cursor inside of the stored procedure? I thank you in advance for your help. Regards, enrichedknowledge@gmail.com

Posted by Enriched Knowledge Jul 18, 2011

how to calculate some data based on the date of appointment or date of increment.. plz... help me out.. if date of increment if greater than date of appointment calculate the data... how to do

Posted by Sutha Raghavan Jan 19, 2011

really its good

Posted by Sutha Raghavan Jan 19, 2011

I don't agree with this statement... table variable just like temp tables are stored in tempdb, ref: http://sqlwithmanoj.wordpress.com/2010/07/20/table-variables-are-not-stored-in-memory-but-in-tempdb/

Posted by Manoj Pandey Dec 14, 2010

thanks for providing such valuable information u save my time

Posted by natraj ankhe Aug 03, 2010
Become a Sponsor
PREMIUM SPONSORS
  • Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
    Finally – a virtual platform that delivers next-generation Windows Server 2008 Hyper-V virtualization technology from a managed hosting partner you can truly depend on. Visit www.maximumasp.com/max for a FREE 30 day trial. Hurry offer ends soon. Climb aboard the MaxV platform and take advantage of High Availability, Intelligent Monitoring, Recurrent Backups, and Scalability – with no hassle or hidden fees. As a managed hosting partner focused solely on Microsoft technologies since 2000, MaximumASP is uniquely qualified to provide the superior support that our business is built on. Unparalleled expertise with Microsoft technologies lead to working directly with Microsoft as first to offer IIS 7 and SQL 2008 betas in a hosted environment; partnering in the Go Live Program for Hyper-V; and product co-launches built on WS 2008 with Hyper-V technology.
6 Months Free & No Setup Fees ASP.NET Hosting!
Become a Sponsor