Domanda

Il problema principale riguarda la modifica dell'indice delle righe in 1,2,3 .. dove ID-contatto e tipo sono gli stessi. ma tutte le colonne possono contenere esattamente gli stessi dati a causa di alcuni ex-dipendenti incasinati e aggiornare tutte le righe per ID contatto e tipo. in qualche modo ci sono righe che non sono incasinate ma le righe dell'indice sono uguali. È il caos totale.

Ho provato a usare un cursore interno con le variabili provenienti dal cursore esterno. Ma sembra che sia bloccato nel cursore interno.

Una parte della query è simile alla seguente:

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)

Quale può essere il problema? @@ FETCH_STATUS è ambiguo o qualcosa del genere?

EDIT: tutto sembra a posto se non uso questo codice all'interno del cursore interno:

UPDATE CONTACTS
SET INDEX_NO = @COUNTER
where current of INNER_CURSOR

EDIT: ecco il quadro generale:

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
È stato utile?

Soluzione 6

Non capisco perfettamente quale fosse il problema con "aggiorna la corrente del cursore " ma si risolve usando l'istruzione fetch due volte per il cursore interno:

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

Altri suggerimenti

Hai una varietà di problemi. Innanzitutto, perché stai usando i tuoi valori @@ FETCH_STATUS specifici? Dovrebbe essere solo @@ FETCH_STATUS = 0.

Secondo, non stai selezionando il tuo cursore interno in nulla. E non riesco a pensare a nessuna circostanza in cui selezioneresti tutti i campi in questo modo: spiegali!

Ecco un esempio da seguire. La cartella ha una chiave primaria di " ClientID " questa è anche una chiave esterna per Attend. Sto solo stampando tutti gli UID di partecipazione, suddivisi per ID client cartella:

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;

Infine, sei SICURO che vuoi fare qualcosa del genere in una procedura memorizzata? È molto facile abusare delle stored procedure e spesso riflette problemi nella caratterizzazione del problema. Il campione che ho fornito, ad esempio, potrebbe essere realizzato molto più facilmente utilizzando le chiamate di selezione standard.

Puoi anche evitare problemi con i cursori nidificati, problemi con i cursori generali e problemi con le variabili globali evitando completamente i cursori.

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

Fai altri recuperi? Dovresti mostrare anche quelli. Ci stai mostrando solo metà del codice.

Dovrebbe apparire come:

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

Inoltre, assicurati di non nominare i cursori allo stesso modo ... e qualsiasi codice (controlla i tuoi trigger) che viene chiamato non utilizza un cursore con lo stesso nome. Ho visto comportamenti strani da parte di persone che usano "theCursor" in più livelli dello stack.

Questo odora di qualcosa che dovrebbe essere fatto con un JOIN invece. Puoi condividere il problema più grande con noi?


Ehi, dovrei essere in grado di riassumere questo in una singola affermazione, ma non ho avuto il tempo di giocarci ancora oggi e potrei non farlo. Nel frattempo, sappi che dovresti essere in grado di modificare la query per il cursore interno per creare i numeri di riga come parte della query utilizzando ROW_NUMBER () . Da lì, è possibile piegare il cursore interno verso l'esterno eseguendo un INNER JOIN su di esso (è possibile unire una query secondaria). Infine, qualsiasi istruzione SELECT può essere convertita in un AGGIORNAMENTO utilizzando questo metodo:

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

Dove [YourTable / Alias] è una tabella o un alias utilizzato nella query di selezione.

Ho avuto lo stesso problema,

quello che devi fare è dichiarare il secondo cursore come: DECLARE [secondo_cursore] Cursore LOCALE per

Vedi " CURSORE LOCALE PER " invece di " CURSORE PER "

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top