2010-01-05 3 views
21

Perché SQL Server non supporta i blocchi TRY-CATCH all'interno di UDF?Perché il blocco TRY-CATCH non è consentito nelle UDF?

Se parliamo di UDF scalari, che sono principalmente utilizzati per calcoli e conversazioni, questo blocco dovrebbe essere usato pesantemente, ma non ce l'abbiamo.

Inoltre, quali soluzioni alternative si utilizzano per questo?

+3

+1 buona domanda – kevchadders

risposta

12

Le UDF in MSSQL non possono avere effetti collaterali, che BOL definisce come "modifica dello stato del database". Questa è una descrizione piuttosto vaga, ma MSSQL considera a quanto pare gli errori per cambiare lo stato del database - questa UDF non può essere compilato:

create function dbo.foo() 
returns int 
as 
begin 
    raiserror('Foo', 16, 1) 
    return 1 
end 
go 

Il messaggio di errore è:

Msg 443, livello 16, stato 14 , Procedura foo, Riga 5 Uso non valido di un operatore di effetti speciali "RAISERROR" all'interno di una funzione.

Se si verifica un errore durante la modifica di uno stato del database, lo si intuisce anche per intercettarlo e gestirlo. Il che non è molto di una spiegazione, lo ammetto.

In termini pratici, tuttavia, è spesso meglio lasciare che il chiamante decida comunque come gestire gli errori. Supponi di scrivere una funzione come questa:

create function dbo.divide (@x int, @y int) 
returns float 
as 
begin 
return @x/cast(@y as float) 
end 

Come gestiresti il ​​caso in cui un'applicazione passa a zero per @y? Se rilevi l'eccezione per zero, cosa farai dopo? Quale valore si può restituire dalla funzione che ha senso per il chiamante, tenendo presente che non si può nemmeno sapere quale applicazione sta chiamando la funzione comunque?

Si potrebbe pensare di restituire NULL, ma gli sviluppatori di applicazioni che utilizzano la funzione concordano? Tutte le loro applicazioni considerano un errore di divisione per zero per avere lo stesso impatto o importanza? Per non parlare del fatto che i NULL in certi punti possono cambiare completamente i risultati di una query, forse in modi che lo sviluppatore dell'applicazione non vuole affatto.

Se sei l'unico sviluppatore, forse non è un problema, ma con più persone diventa rapidamente uno.

+1

Volevo riprodurre il comportamento di TRY_CAST scrivendo la mia UDF: –

1

Come soluzione, chiamerei l'UDF di TRY/CATCH all'interno di una stored procedure.

+2

Grazie per la risposta, ma quando si scrive un UDF di solito viene riutilizzato da altre persone. La tua soluzione funziona se scrivo sia la funzione che il chiamante, ma non puoi mai essere sicuro che altri chiameranno la tua procedura nel modo giusto. –

+0

true ... penso che ck abbia fatto un buon punto sul potenziale di essere chiamato migliaia di volte, quindi l'overhead di un try/catch potrebbe essere enorme. – kevchadders

1

Forse è perché l'overhead è troppo - una funzione scalare può essere chiamata su una colonna come parte di una selezione e quindi essere chiamata migliaia di volte. Se ci fosse un ragionevole sovraccarico per consentire di provarlo/catturarlo lo rallenterebbe in modo orrendo.

+0

+1 buon punto sulle spese generali – kevchadders

+3

Sì, ck, ma potremmo dire lo stesso per molti altri aspetti della programmazione (i cursori vengono in mente). Direi che spetta allo sviluppatore che scrive la funzione decidere se è l'implementazione e il possibile utilizzo sarà overhead e codice di conseguenza. –