2009-09-11 3 views
15

Diciamo che ho un innesco come questo:T-SQL: Un modo corretto di CHIUDERE il cursore/DEALLOCATE nel trigger di aggiornamento

CREATE TRIGGER trigger1 
    ON [dbo].[table1] 
    AFTER UPDATE 
AS 
BEGIN    
    --declare some vars 
    DECLARE @Col1 SMALLINT 
    DECLARE @Col1 TINYINT 

    --declare cursor   
    DECLARE Cursor1 CURSOR FOR 
    SELECT Col1, Col2 FROM INSERTED    

    --do the job 
    OPEN Cursor1 
    FETCH NEXT FROM Cursor1 INTO @Col1, @Col2 

    WHILE @@FETCH_STATUS = 0 
    BEGIN 
     IF ...something... 
     BEGIN   
      EXEC myProc1 @param1 = @Col1, @Param2 = @Col2 
     END    
     ELSE 
     IF ...something else... 
     BEGIN   
      EXEC myProc2 @param1 = @Col1, @Param2 = @Col2 
     END  

     FETCH NEXT FROM Cursor1 INTO @Col1, @Col2    
    END 

    --clean it up  
    CLOSE Cursor1 
    DEALLOCATE Cursor1     
END 

voglio essere sicuro che Cursor1 è sempre chiuso e deallocato. Persino myProc1 o myProc2 non riescono.

Devo usare il blocco try/catch?

+0

[Lettura obbligatoria] (http://www.sommarskog.se/error-handling-I.html). –

risposta

15

Sì, utilizzare TRY/CATCH ma assicurati di deallocarti ecc. Dopo. Sfortunatamente, non c'è ancora in SQL Server.

Tuttavia, suggerisco avvolgendo questo in un altro try/catch

CREATE TRIGGER trigger1 ON [dbo].[table1] AFTER UPDATE 
AS 
BEGIN       
    --declare some vars 
    DECLARE @Col1 SMALLINT, @Col1 TINYINT 

    BEGIN TRY 
     --declare cursor    
     DECLARE Cursor1 CURSOR FOR 
     SELECT Col1, Col2 FROM INSERTED      

     --do the job 
     OPEN Cursor1 
     FETCH NEXT FROM Cursor1 INTO @Col1, @Col2 

     WHILE @@FETCH_STATUS = 0 
     BEGIN 
      IF ...something... 
        EXEC myProc1 @param1 = @Col1, @Param2 = @Col2 
      ELSE 
      IF ...something else... 
        EXEC myProc2 @param1 = @Col1, @Param2 = @Col2 

      FETCH NEXT FROM Cursor1 INTO @Col1, @Col2        
     END 
    END TRY 
    BEGIN CATCH 
     --do what you have to 
    END CATCH 

    BEGIN TRY 
     --clean it up    
     CLOSE Cursor1 
     DEALLOCATE Cursor1         
    END TRY 
    BEGIN CATCH 
     --do nothing 
    END CATCH 
END 

Se un cursore in un trigger è una buona idea è una questione diversa ...

+0

Qual è il tuo ragionamento per avvolgere la pulizia del cursore in un blocco try/catch quando la cattura non fa nulla? –

+4

@NickDeVore: perché il cursore potrebbe essere già chiuso, a seconda di come proc1 o proc2 falliscono (in un trigger, forse try/catch ecc.). Meglio prevenire che curare. – gbn

+0

È possibile utilizzare la sintassi TRY/CATCH nel trigger? Quello che so è che quando si verifica un errore in un trigger l'intera transazione fallisce, se ci sono try/catch o no. –

1

Quello che dovresti fare non usare mai un cursore in un trigger. Scrivere invece un codice basato su set corretto. Se qualcuno ha importato dei dati nella tua tabella di 100.000 nuovi record, bloccherai la tabella per ore e interromperai il tuo database. È una pratica molto povera usare un cursore in un trigger.

+1

Se qualcuno ha importato dati in questa tabella di 100.000 nuovi record, non bloccherebbe affatto la mia tabella (perché questo è un trigger dopo l'aggiornamento;) Ma seriamente. Non fraintendermi. Capisco perfettamente cosa intendi e hai ragione. Non userei mai un cursore in un trigger a meno che non sia assolutamente necessario e nel mio caso lo è. In teoria solo poche righe possono essere aggiornate contemporaneamente dalla mia app (a meno che qualcuno non aggiorni da Management Studio). Tutto funziona perfettamente (e veloce) ma mi chiedo cosa succederebbe se uno dei miei SP fallisse. Dovrei preoccuparmi del tutto? – Novitzky

+0

Suggerirei di eseguire il test apportando una modifica al proc o al data inserto che garantiranno il fallimento del proc. Allora saprai cosa accadrà. – HLGEM

+0

Grazie. Questo è esattamente quello che farò. Come ho detto prima devo usare il cursore (altrimenti ci sarebbero troppe modifiche nella mia app) ma posso cambiare i miei SP. Grazie comunque. – Novitzky

Problemi correlati