2010-01-05 64 views

回答

12

MSSQL中的UDF不允許有副作用,BOL將其定義爲「更改數據庫狀態」。這是一個相當模糊的描述,但MSSQL顯然認爲錯誤更改數據庫的狀態 - 這UDF不會編譯:

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

的錯誤信息是:

消息443,級別16,狀態14 ,程序 foo,第5行在功能中使用 副作用運算符'RAISERROR' 無效。

如果提出錯誤被認爲是改變數據庫狀態,那麼誘捕和處理一個錯誤也是可以的。我承認這不是一個解釋。

但實際上,通常最好讓調用者決定如何處理錯誤。假設你寫這樣一個函數:

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

你將如何處理應用程序對@y通過零的情況?如果您通過零例外來捕獲除數,那麼接下來要做什麼?你可以從對調用者有意義的函數中返回什麼樣的值,記住你甚至可能不知道哪個應用程序正在調用你的函數?

您可能會想到返回NULL,但使用您的函數的應用程序開發人員會同意嗎?他們的所有應用程序是否都將零差錯劃分爲相同的影響或重要性?更不用說某些地方的NULL可以完全改變查詢的結果,也許應用程序開發人員完全不需要。

如果你是唯一的開發者,也許這不是問題,但是隨着更多的人迅速成爲一個開發者。

+1

我想通過編寫自己的UDF來重現TRY_CAST的行爲: – 2014-11-12 16:02:37

1

作爲解決方法,我會在存儲過程中從TRY/CATCH調用UDF。

+2

感謝您的回答,但是當您編寫UDF時,通常會被其他人重複使用。 如果我寫入函數和調用者,你的解決方案就可以工作,但你永遠無法確定別人會以正確的方式調用你的過程。 – 2010-01-05 11:30:43

+0

是真的......我認爲ck對它被稱爲數千次的潛力提出了一個很好的觀點,所以try/catch的開銷可能是巨大的。 – kevchadders 2010-01-05 13:55:31

1

也許是因爲開銷太大 - 標量函數可能作爲select的一部分在列上調用,因此被稱爲數千次。如果有一個合理的開銷來允許try/catch,它會使其變得非常糟糕。

+0

+1關於開銷的好處 – kevchadders 2010-01-05 13:56:03

+3

是的,ck,但是我們可以說在編程的許多其他方面(遊標都會想起來)是一樣的。 我想說這取決於開發人員編寫的函數來決定它的實現和可能的用法是開銷,並相應地編碼。 – 2010-01-05 14:52:36