Blog coding and discussion of coding about JavaScript, PHP, CGI, general web building etc.

Tuesday, May 10, 2016

Cursor inside cursor

Cursor inside cursor


Main problem is about changing the index of rows to 1,2,3.. where contact-id and type is the same. but all columns can contain exactly the same data because of some ex-employee messed up and update all rows by contact-id and type. somehow there are rows that aren't messed but index rows are same. It is total chaos.

I tried to use an inner cursor with the variables coming from the outer cursor. But It seems that its stuck in the inner cursor.

A part of the query looks like this:

Fetch NEXT FROM OUTER_CURSOR INTO @CONTACT_ID,  @TYPE  While (@@FETCH_STATUS <> -1)  BEGIN  IF (@@FETCH_STATUS <> -2)        DECLARE INNER_CURSOR Cursor       FOR       SELECT * FROM CONTACTS      where CONTACT_ID = @CONTACT_ID      and TYPE = @TYPE         Open INNER_CURSOR         Fetch NEXT FROM INNER_CURSOR       While (@@FETCH_STATUS <> -1)      BEGIN      IF (@@FETCH_STATUS <> -2)  

What can be the problem? Is @@FETCH_STATUS ambiguous or something?

EDIT: everything looks fine if i don't use this code inside inner cursor:

UPDATE CONTACTS  SET INDEX_NO = @COUNTER  where current of INNER_CURSOR  

EDIT: here is the big picture:

BEGIN TRAN    DECLARE @CONTACT_ID VARCHAR(15)  DECLARE @TYPE VARCHAR(15)  DECLARE @INDEX_NO  SMALLINT  DECLARE @COUNTER SMALLINT  DECLARE @FETCH_STATUS INT     DECLARE OUTER_CURSOR CURSOR     FOR     SELECT CONTACT_ID, TYPE, INDEX_NO FROM CONTACTS  WHERE    CONTACT_ID IN (SELECT CONTACT_ID FROM dbo.CONTACTS  WHERE CONTACT_ID IN(...)  GROUP BY CONTACT_ID, TYPE, INDEX_NO  HAVING COUNT(*) > 1    OPEN OUTER_CURSOR     FETCH NEXT FROM OUTER_CURSOR INTO @CONTACT_ID,  @TYPE, @INDEX_NO  WHILE (@@FETCH_STATUS <> -1)  BEGIN  IF (@@FETCH_STATUS <> -2)    SET @COUNTER = 1        	DECLARE INNER_CURSOR CURSOR       	FOR       	SELECT * FROM CONTACTS      	WHERE CONTACT_ID = @CONTACT_ID      	AND TYPE = @TYPE       	FOR UPDATE         	OPEN INNER_CURSOR         	FETCH NEXT FROM INNER_CURSOR         	WHILE (@@FETCH_STATUS <> -1)      	BEGIN      	IF (@@FETCH_STATUS <> -2)        	UPDATE CONTACTS      	SET INDEX_NO = @COUNTER      	WHERE CURRENT OF INNER_CURSOR        	SET @COUNTER = @COUNTER + 1        	FETCH NEXT FROM INNER_CURSOR       	END      	CLOSE INNER_CURSOR      	DEALLOCATE INNER_CURSOR    FETCH NEXT FROM OUTER_CURSOR INTO @CONTACT_ID,  @TYPE, @INDEX_NO  END  CLOSE OUTER_CURSOR  DEALLOCATE OUTER_CURSOR    COMMIT TRAN  

Answer by David B for Cursor inside cursor


Do you do any more fetches? You should show those as well. You're only showing us half the code.

It should look like:

FETCH NEXT FROM @Outer INTO ...  WHILE @@FETCH_STATUS = 0  BEGIN    DECLARE @Inner...    OPEN @Inner    FETCH NEXT FROM @Inner INTO ...    WHILE @@FETCH_STATUS = 0    BEGIN    ...      FETCH NEXT FROM @Inner INTO ...    END    CLOSE @Inner    DEALLOCATE @Inner    FETCH NEXT FROM @Outer INTO ...  END  CLOSE @Outer  DEALLOCATE @Outer  

Also, make sure you do not name the cursors the same... and any code (check your triggers) that gets called does not use a cursor that is named the same. I've seen odd behavior from people using 'theCursor' in multiple layers of the stack.

Answer by Mark Brittingham for Cursor inside cursor


You have a variety of problems. First, why are you using your specific @@FETCH_STATUS values? It should just be @@FETCH_STATUS = 0.

Second, you are not selecting your inner Cursor into anything. And I cannot think of any circumstance where you would select all fields in this way - spell them out!

Here's a sample to go by. Folder has a primary key of "ClientID" that is also a foreign key for Attend. I'm just printing all of the Attend UIDs, broken down by Folder ClientID:

Declare @ClientID int;  Declare @UID int;    DECLARE Cur1 CURSOR FOR  	SELECT ClientID From Folder;    OPEN Cur1  FETCH NEXT FROM Cur1 INTO @ClientID;  WHILE @@FETCH_STATUS = 0  BEGIN  	PRINT 'Processing ClientID: ' + Cast(@ClientID as Varchar);  	DECLARE Cur2 CURSOR FOR  		SELECT UID FROM Attend Where ClientID=@ClientID;  	OPEN Cur2;  	FETCH NEXT FROM Cur2 INTO @UID;  	WHILE @@FETCH_STATUS = 0  	BEGIN  		PRINT 'Found UID: ' + Cast(@UID as Varchar);  		FETCH NEXT FROM Cur2 INTO @UID;  	END;  	CLOSE Cur2;  	DEALLOCATE Cur2;  	FETCH NEXT FROM Cur1 INTO @ClientID;  END;  PRINT 'DONE';  CLOSE Cur1;  DEALLOCATE Cur1;  

Finally, are you SURE you want to be doing something like this in a stored procedure? It is very easy to abuse stored procedures and often reflects problems in characterizing your problem. The sample I gave, for example, could be far more easily accomplished using standard select calls.

Answer by cmsjr for Cursor inside cursor


You could also sidestep nested cursor issues, general cursor issues, and global variable issues by avoiding the cursors entirely.

declare @rowid int  declare @rowid2 int  declare @id int  declare @type varchar(10)  declare @rows int  declare @rows2 int  declare @outer table (rowid int identity(1,1), id int, type varchar(100))  declare @inner table (rowid int  identity(1,1), clientid int, whatever int)    insert into @outer (id, type)   Select id, type from sometable    select @rows = count(1) from @outer  while (@rows > 0)  Begin      select top 1 @rowid = rowid, @id  = id, @type = type      from @outer      insert into @innner (clientid, whatever )       select clientid whatever from contacts where contactid = @id      select @rows2 = count(1) from @inner      while (@rows2 > 0)      Begin      	select top 1 /* stuff you want into some variables */      	/* Other statements you want to execute */      	delete from @inner where rowid = @rowid2      	select @rows2 = count(1) from @inner      End        delete from @outer where rowid = @rowid      select @rows = count(1) from @outer  End  

Answer by Joel Coehoorn for Cursor inside cursor


This smells of something that should be done with a JOIN instead. Can you share the larger problem with us?


Hey, I should be able to get this down to a single statement, but I haven't had time to play with it further yet today and may not get to. In the mean-time, know that you should be able to edit the query for your inner cursor to create the row numbers as part of the query using the ROW_NUMBER() function. From there, you can fold the inner cursor into the outer by doing an INNER JOIN on it (you can join on a sub query). Finally, any SELECT statement can be converted to an UPDATE using this method:

UPDATE [YourTable/Alias]     SET [Column] = q.Value  FROM  (     ... complicate select query here ...  ) q  

Where [YourTable/Alias] is a table or alias used in the select query.

Answer by Orkun Balkanc? for Cursor inside cursor


I don't fully understand what was the problem with the "update current of cursor" but it is solved by using the fetch statement twice for the inner cursor:

FETCH NEXT FROM INNER_CURSOR    WHILE (@@FETCH_STATUS <> -1)  BEGIN    UPDATE CONTACTS  SET INDEX_NO = @COUNTER  WHERE CURRENT OF INNER_CURSOR    SET @COUNTER = @COUNTER + 1    FETCH NEXT FROM INNER_CURSOR  FETCH NEXT FROM INNER_CURSOR  END  


Fatal error: Call to a member function getElementsByTagName() on a non-object in D:\XAMPP INSTALLASTION\xampp\htdocs\endunpratama9i\www-stackoverflow-info-proses.php on line 72

0 comments:

Post a Comment

Popular Posts

Powered by Blogger.