Link to home
Start Free TrialLog in
Avatar of Tyler
TylerFlag for United States of America

asked on

how to change a cursor to something more efficiant

How can I improve the cursor or change it to something more performance based?

here is the cursor

    DECLARE @rn INT;
    DECLARE @nextrn INT;

    DECLARE cur CURSOR
    FOR
        SELECT   rownum
        FROM     #tmpHCLC
        WHERE    break_ind = 'Y'
            GROUP BY rownum
            ORDER BY rownum;

    OPEN cur;
    FETCH NEXT FROM cur INTO @rn;
    WHILE @@FETCH_STATUS = 0
        BEGIN

            SET @nextrn = ( SELECT TOP 1
                                    rownum
                            FROM    #tmpHCLC
                            WHERE   break_ind = 'Y'
                                    AND rownum > @rn
                          );

            UPDATE   #tmpHCLC
            SET     concurrent_ind = concurrent_ind + CAST(@rn AS VARCHAR)
            WHERE   concurrent_ind = 'Y'
                    AND rownum >= @rn
                    AND rownum < @nextrn;

            FETCH NEXT FROM cur INTO @rn;
        END;
    CLOSE cur;
    DEALLOCATE cur;
Avatar of Pawan Kumar
Pawan Kumar
Flag of India image

Are you using Oracle?
Avatar of Tyler

ASKER

This is  Microsoft SQL server 2014
Hi,
Can  you please provide me some sample data and the expected output?
Hi,
Please try this..

DECLARE @rn INT;
DECLARE @nextrn INT;

;WITH CTE AS
(
	SELECT   rownum
	FROM     #tmpHCLC
	WHERE    break_ind = 'Y'
	GROUP BY rownum
)
,CTE1 AS 
(
	SELECT b.rownum curr, b.rownum nex FROM CTE b
	CROSS APPLY
	( 
		SELECT TOP 1 a.rownum
		FROM    #tmpHCLC a
		WHERE   a.break_ind = 'Y'
		AND a.rownum > a.rownum
	)
)

UPDATE   c 
SET   c.concurrent_ind = c.concurrent_ind + CAST(@rn AS VARCHAR)
FROM #tmpHCLC c INNER JOIN CTE1 c1 ON c.rownum >= c1.curr AND c.rownum < c1.nex
WHERE   c.concurrent_ind = 'Y'
    

Open in new window


Hope it helps!
Updated.. Please try..

DECLARE @rn INT;
DECLARE @nextrn INT;

;WITH CTE AS
(
	SELECT   rownum
	FROM     #tmpHCLC
	WHERE    break_ind = 'Y'
	GROUP BY rownum
)
,CTE1 AS 
(
	SELECT b.rownum curr, k.rownum nex FROM CTE b
	CROSS APPLY
	( 
		SELECT TOP 1 a.rownum
		FROM    #tmpHCLC a
		WHERE   a.break_ind = 'Y'
		AND a.rownum > a.rownum
	)k
)
UPDATE   c 
SET   c.concurrent_ind = c.concurrent_ind + CAST(@rn AS VARCHAR)
FROM #tmpHCLC c INNER JOIN CTE1 c1 ON c.rownum >= c1.curr AND c.rownum < c1.nex
WHERE   concurrent_ind = 'Y'
    

Open in new window


Hope it helps!
Avatar of Scott Pletcher
The code as it's written will never UPDATE anything, because  @nextrn is never given a value, and thus it remains NULL, which means that in the the UPDATE, the WHERE condition " AND rownum < @nextrn" can never be true, so the UPDATE can never actually UPDATE any row.
Avatar of Tyler

ASKER

would this not accomplish the same thing as the cursor the way its written?

UPDATE a
      SET a.concurrent_ind = 'Y'+ cast(a.rownum AS VARCHAR(MAX))
      FROM #tmpHCLC a
      WHERE a.concurrent_ind = 'y' AND a.break_ind = 'Y'
ASKER CERTIFIED SOLUTION
Avatar of Pawan Kumar
Pawan Kumar
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Tyler

ASKER

This made it very simple and elegant to replace a cursor that was created by another application.  Remember to always avoid cursors when ever possible It can be a major performance drain if no proper indexes exist.
Sorry about the previous comment, didn't have time then to look closely enough at the code.

But the new code is not necessarily the same as the original code:

In the original code, rows after the first row with "break_ind = 'Y'" do not require the break_ind to be set in order for the concurrent_ind to be updated, but of course in the new code every row would require break_ind to be set as well.