SQLUSA
SAVE UP TO 50% ON COMBOS
FREE TRIAL
CLICK HERE TO ORDER

SQL Server 2008 Best Practices
SQL Server 2005 Best Practices

How to construct nested cursors?

Execute the following Microsoft SQL Server T-SQL example scripts in Management Studio Query Editor to demonstrate the construction of cursor and nested cursors logic.

Cursor solutions do not scale well for large data sets. For such cases, it is better to use set-based operations. See set-based solution T-SQL script following the Purchase Order nested cursors demo.

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

-- SQL Cursor Syntax - cursor loop syntax - using t-sql cursor

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

USE AdventureWorks2008;

DECLARE curSubcategory CURSOR READ_ONLY              -- sql declare cursor

FOR SELECT ProductSubcategoryID, Subcategory=Name

FROM Production.ProductSubcategory ORDER BY Subcategory

DECLARE @Subcategory varchar(40), @PSID int

OPEN curSubcategory

FETCH NEXT FROM curSubcategory INTO @PSID, @Subcategory  -- sql fetch cursor

WHILE (@@fetch_status = 0)                    -- sql cursor fetch_status

BEGIN -- begin cursor loop

/***** USER DEFINED CODE HERE - POSSIBLY NESTED CURSOR *****/

            DECLARE @Msg varchar(128)

            SELECT @Msg = 'ProductSubcategory info: ' + @Subcategory + ' '+

                   CONVERT(varchar,@PSID)

            PRINT @Msg

FETCH NEXT FROM curSubcategory INTO @PSID, @Subcategory   -- sql fetch cursor

END -- end cursor loop

CLOSE curSubcategory

DEALLOCATE curSubcategory

GO

/* Partial output in Messages

 

ProductSubcategory info: Bib-Shorts 18

ProductSubcategory info: Bike Racks 26

ProductSubcategory info: Bike Stands 27

ProductSubcategory info: Bottles and Cages 28

ProductSubcategory info: Bottom Brackets 5

ProductSubcategory info: Brakes 6

*/

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


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

-- T SQL Search All Text & XML Columns in All Tables

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

-- SQL nested cursors - sql server nested cursor - transact sql nested cursor

USE AdventureWorks;

GO

-- SQL Server create stored procedure with nested cursors

CREATE PROC sprocSearchKeywordInAllTables  @Keyword NVARCHAR(64)

AS

  BEGIN

    SET NOCOUNT  ON

    DECLARE  @OutputLength VARCHAR(4),

             @NolockOption CHAR(8)

         SET @OutputLength = '256'

         SET @NolockOption = ''

         -- SET @NolockOption =  '(NOLOCK)'

    DECLARE  @DynamicSQL   NVARCHAR(MAX),

             @SchemaTableName   NVARCHAR(256),

             @SchemaTableColumn NVARCHAR(128),

             @SearchWildcard    NVARCHAR(128)

         SET @SearchWildcard = QUOTENAME('%' + @Keyword + '%',CHAR(39)+CHAR(39))

         PRINT @SearchWildcard

    DECLARE  @SearchResults  TABLE(

                                   SchemaTableColumn NVARCHAR(384),

                                   TextWithKeyword   NVARCHAR(MAX)

                                   )

 

    DECLARE curAllTables CURSOR  FOR

    SELECT   QUOTENAME(TABLE_SCHEMA) + '.' + QUOTENAME(TABLE_NAME) AS ST

    FROM     INFORMATION_SCHEMA.TABLES

    WHERE    TABLE_TYPE = 'BASE TABLE'

             AND OBJECTPROPERTY(OBJECT_ID(QUOTENAME(TABLE_SCHEMA) + '.'

             + QUOTENAME(TABLE_NAME)), 'IsMSShipped') != 1

    ORDER BY ST

    OPEN curAllTables

    FETCH NEXT FROM curAllTables

    INTO @SchemaTableName

    

    WHILE (@@FETCH_STATUS = 0) -- Outer cursor loop

      BEGIN

        PRINT @SchemaTableName

        SET @SchemaTableColumn = ''

        DECLARE curAllColumns CURSOR  FOR -- Nested cursor

        SELECT   QUOTENAME(COLUMN_NAME)

        FROM     INFORMATION_SCHEMA.COLUMNS

        WHERE    TABLE_NAME = PARSENAME(@SchemaTableName,1)

                 AND TABLE_SCHEMA = PARSENAME(@SchemaTableName,2)

                 AND DATA_TYPE IN ('varchar','nvarchar','char','nchar','xml')

        ORDER BY ORDINAL_POSITION

        OPEN curAllColumns

        FETCH NEXT FROM curAllColumns

        INTO @SchemaTableColumn

        WHILE (@@FETCH_STATUS = 0) -- Inner cursor loop (nested cursor while)

          BEGIN

            PRINT '  ' + @SchemaTableColumn

            SET @DynamicSQL = 'SELECT ''' + @SchemaTableName + '.' +

              @SchemaTableColumn + ''', LEFT(CONVERT(nvarchar(max),' +

              @SchemaTableColumn + '),' + @OutputLength + ')  FROM ' +

              @SchemaTableName + ' '+@NolockOption+

              ' WHERE CONVERT(nvarchar(max),' + @SchemaTableColumn +

              ') LIKE ' + @SearchWildcard

            INSERT INTO @SearchResults

            EXEC sp_executeSQL  @DynamicSQL

            FETCH NEXT FROM curAllColumns

            INTO @SchemaTableColumn

          END  -- Inner cursor loop

        CLOSE curAllColumns

        DEALLOCATE curAllColumns

        FETCH NEXT FROM curAllTables

        INTO @SchemaTableName

      END  -- Outer cursor loop

    CLOSE curAllTables

    DEALLOCATE curAllTables

   

    SELECT DISTINCT SchemaTableColumn, TextWithKeyWord FROM   @SearchResults

  END

GO

 

EXEC sprocSearchKeywordInAllTables  'Hamilton'

EXEC sprocSearchKeywordInAllTables  'Sánchez'

EXEC sprocSearchKeywordInAllTables  'O''Donnell'

EXEC sprocSearchKeywordInAllTables  'Certification'

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

The following nested cursors consist of an outer cursor for purchase orders header info and an inner cursor for the details of each purchase order. It is an example for MS SQL nested cursor loop.

------------
-- SQL Server Nested Cursors example - transact sql nested cursor

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

-- SQL nested cursors - transact sql fetch_status - transact sql while loop

-- SQL nesting cursors - transact sql fetch next

-- T-SQL script for execution timing setup

USE AdventureWorks;

DBCC DROPCLEANBUFFERS

DECLARE @StartTime datetime

SET @StartTime = getdate()

 

-- Setup local variables

DECLARE     @IterationID INT,

            @OrderDetail VARCHAR(max),

            @ProductName VARCHAR(10)

 

-- Setup table variable

DECLARE @Result TABLE (PurchaseOrderID INT, OrderDetail VARCHAR(max))

 

 

-- OUTER CURSOR declaration - transact sql declare cursor

DECLARE curOrdersForReport CURSOR FOR

SELECT PurchaseOrderID

FROM Purchasing.PurchaseOrderHeader

WHERE Year(OrderDate) = 2004

  AND Month(OrderDate) = 2

ORDER BY PurchaseOrderID

 

OPEN curOrdersForReport

FETCH NEXT FROM curOrdersForReport INTO @IterationID

PRINT 'OUTER LOOP START'

 

WHILE (@@FETCH_STATUS = 0) -- sql cursor fetch_status

BEGIN

      SET @OrderDetail = ''

 

-- INNER CURSOR declaration - transact sql declare cursor

-- SQL Nested Cursor - sql cursor nested - cursor nesting

 

      DECLARE curDetailList CURSOR FOR

      SELECT p.productNumber

      FROM Purchasing.PurchaseOrderDetail pd

      INNER JOIN Production.Product p

      ON pd.ProductID = p.ProductID

      WHERE pd.PurchaseOrderID = @IterationID

      ORDER BY PurchaseOrderDetailID

 

      OPEN curDetailList

      FETCH NEXT FROM curDetailList INTO @ProductName

      PRINT 'INNER LOOP START'

 

      WHILE (@@FETCH_STATUS = 0)

      BEGIN

            SET @OrderDetail = @OrderDetail + @ProductName + ', '

            FETCH NEXT FROM curDetailList INTO @ProductName

            PRINT 'INNER LOOP'

      END -- inner while

 

      CLOSE curDetailList

      DEALLOCATE curDetailList

 

      -- Truncate trailing comma

      SET @OrderDetail = left(@OrderDetail, len(@OrderDetail)-1)

      INSERT INTO @Result VALUES (@IterationID, @OrderDetail)

 

      FETCH NEXT FROM curOrdersForReport INTO @IterationID

      PRINT 'OUTER LOOP'

END -- outer while

CLOSE curOrdersForReport

DEALLOCATE curOrdersForReport

 

-- Publish results

SELECT * FROM @Result ORDER BY PurchaseOrderID

 

-- Timing result

SELECT ExecutionMsec = datediff(millisecond, @StartTime, getdate())

GO

-- 220 msecs

 

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

-- Equivalent set-based operations solution

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

 

-- Execution timing setup

DBCC DROPCLEANBUFFERS

DECLARE @StartTime datetime

SET @StartTime = getdate()

 

-- SQL comma-limited list generation

-- SQL nested select statement

-- SQL FOR XML PATH

SELECT

      poh.PurchaseOrderID,

      OrderDetail = Stuff((

-- SQL correlated subquery

      SELECT ', ' + ProductNumber as [text()]

      FROM Purchasing.PurchaseOrderDetail pod

      INNER JOIN Production.Product p

      ON pod.ProductID = p.ProductID

      WHERE pod.PurchaseOrderID = poh.PurchaseOrderID

      ORDER BY PurchaseOrderDetailID

      FOR XML PATH ('')), 1, 1, '')

FROM Purchasing.PurchaseOrderHeader poh

WHERE Year(OrderDate) = 2004

  AND Month(OrderDate) = 2

ORDER BY PurchaseOrderID ;

 

-- Timing result

SELECT ExecutionMsec = datediff(millisecond, @StartTime, getdate())

GO

-- 110 msecs

 

 

/* Partial results

 

PurchaseOrderID   OrderDetail

1696              GT-0820, GT-1209

1697              HN-6320, HN-7161, HN-7162, HN-8320, HN-9161, HN-9168

1698              NI-4127

1699              RM-T801

1700              LI-1201, LI-1400, LI-3800

1701              TI-R982, TI-T723
*/

 

The World Leader in SQL Server 2008 Training
The future is just a CLICK away. Your future!
 
SQLUSA.com Home Page

Copyright 2005-2010, SMI Corp. All Rights Reserved.

SQL Server 2008 is a program product of Microsoft Corporation.
SQL Server 2005 is a program product of Microsoft Corporation.
SQL Server 2000 is a program product of Microsoft Corporation.