wake-up-neo.com

Cursor innerhalb des Cursors

Das Hauptproblem besteht darin, den Index der Zeilen auf 1,2,3 zu ändern. Dabei sind Kontakt-ID und Typ identisch. Alle Spalten können jedoch exakt die gleichen Daten enthalten, da einige Mitarbeiter verwirrt sind und alle Zeilen nach Kontakt-ID und Typ aktualisieren. Irgendwie gibt es Zeilen, die nicht durcheinander gebracht werden, aber Indexzeilen sind gleich. Es ist totales Chaos. 

Ich habe versucht, einen inneren Cursor mit den vom äußeren Cursor kommenden Variablen zu verwenden. Aber es scheint, dass es im inneren Cursor stecken bleibt.

Ein Teil der Abfrage sieht folgendermaßen aus:

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)

Was kann das Problem sein? Ist @@ FETCH_STATUS mehrdeutig oder etwas?

BEARBEITEN: alles sieht gut aus, wenn ich diesen Code nicht innerhalb des inneren Cursors verwende:

UPDATE CONTACTS
SET INDEX_NO = @COUNTER
where current of INNER_CURSOR

EDIT: hier ist das große Bild:

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
25
Orkun Balkancı

Ich verstehe das Problem mit dem "Aktualisierungsstrom des Cursors" nicht vollständig, aber es wird durch zweimaliges Verwenden der fetch-Anweisung für den inneren Cursor gelöst :

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
0
Orkun Balkancı

Sie haben eine Vielzahl von Problemen. Warum verwenden Sie Ihre spezifischen @@ FETCH_STATUS-Werte? Es sollte nur @@ FETCH_STATUS = 0 sein.

Zweitens wählen Sie Ihren inneren Cursor nicht in. Ich kann mir keine Umstände vorstellen, unter denen Sie alle Felder auf diese Weise auswählen würden - buchstabieren Sie sie!

Hier ist ein Beispiel, an dem Sie vorbeikommen können. Ordner hat einen Primärschlüssel von "ClientID", der auch ein Fremdschlüssel für Attend ist. Ich drucke nur alle Attend-UIDs, aufgeschlüsselt nach Ordner-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 [email protected];
    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;

Sind Sie schließlich SICHER, wenn Sie in einer gespeicherten Prozedur so etwas tun möchten? Es ist sehr einfach, gespeicherte Prozeduren zu missbrauchen, und spiegelt häufig Probleme bei der Charakterisierung Ihres Problems wider. Das Beispiel, das ich gegeben habe, könnte mit Standard-Select-Aufrufen viel einfacher durchgeführt werden.

57

Sie können auch verschachtelte Cursorprobleme, allgemeine Cursorprobleme und Probleme mit globalen Variablen umgehen, indem Sie die Cursor vollständig vermeiden. 

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
9
cmsjr

Machst du noch mehr? Das solltest du auch zeigen. Sie zeigen uns nur den halben Code.

Es sollte so aussehen:

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

Stellen Sie außerdem sicher, dass Sie den Cursorn nicht den gleichen Namen geben ... und der Code (überprüfen Sie die Trigger), der aufgerufen wird, verwendet keinen Cursor mit dem gleichen Namen. Ich habe ein seltsames Verhalten von Leuten gesehen, die 'theCursor' in mehreren Schichten des Stapels verwendet haben.

2
Amy B

Dies riecht nach etwas, das stattdessen mit einem JOIN erledigt werden sollte. Können Sie das größere Problem mit uns teilen?


Hey, ich sollte in der Lage sein, dies auf eine einzige Aussage zu bringen, aber ich hatte heute keine Zeit mehr damit zu spielen und komme vielleicht nicht dazu. In der Zwischenzeit sollten Sie wissen, dass Sie die Abfrage für Ihren inneren Cursor bearbeiten können, um die Zeilennummern als Teil der Abfrage mithilfe der Funktion ROW_NUMBER () zu erstellen. Von dort aus können Sie den inneren Cursor in den äußeren Bereich falten, indem Sie einen INNER JOIN-Befehl ausführen (Sie können an einer Unterabfrage teilnehmen). Schließlich kann jede SELECT-Anweisung mit dieser Methode in ein UPDATE konvertiert werden:

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

Dabei ist [YourTable/Alias] eine Tabelle oder ein Alias, der in der Auswahlabfrage verwendet wird. 

2
Joel Coehoorn

Ich hatte das gleiche Problem,

sie müssen den zweiten Cursor als deklarieren: DECLARE [second_cursor] Cursor LOCAL For

Sie sehen "CURSOR LOCAL FOR" anstelle von "CURSOR FOR"

0
Julian Salinas