为什么在UDF中不允许TRY-CATCH阻塞?

时间:2010-01-05 10:49:02

标签: tsql user-defined-functions

为什么SQL Server不支持UDF中的TRY-CATCH块?

如果我们谈论主要用于计算和对话的标量UDF,应该大量使用此块,但我们没有。

此外,您使用了哪些变通办法?

4 个答案:

答案 0 :(得分:12)

MSSQL中的UDF不允许有副作用,BOL将其定义为“更改数据库状态”。这是一个相当模糊的描述,但MSSQL显然认为错误改变了数据库状态 - 这个UDF不能编译:

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

错误消息是:

  

Msg 443,Level 16,State 14,Procedure   foo,第5行a的使用无效   副作用操作员'RAISERROR'   在一个函数内。

如果提出错误被认为是改变了数据库状态,那么可能也会陷阱和处理错误。我承认,这不是一个很好的解释。

但实际上,通常最好让调用者决定如何处理错误。假设你写了这样一个函数:

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

你如何处理应用程序为@y传递零的情况?如果你得到除以零的异常,你接下来要做什么?您可以从对调用者有意义的函数返回什么值,请记住您甚至不知道哪个应用程序正在调用您的函数?

您可能会想到返回NULL,但使用您的函数的应用程序开发人员会同意吗?他们的所有应用程序是否都认为除以零误差具有相同的影响或重要性?更不用说某些地方的NULL可以完全改变查询的结果,可能是应用程序开发人员根本不想要的方式。

如果你是唯一的开发者,也许这不是一个问题,但随着更多的人,它很快就会成为一个。

答案 1 :(得分:2)

作为一种解决方法,我会在存储过程中从TRY / CATCH调用UDF。

答案 2 :(得分:1)

可能是因为开销过多 - 可以在列上调用标量函数作为select的一部分,因此可以调用数千次。如果有一个合理的开销来允许尝试/捕获它会使它惨不忍睹。

答案 3 :(得分:0)

使用SQLServer 2012,您可以尝试exec sp_your_procedure_with_try_catch,它对我有用。

实际上,我的几个触发器在一个按键SP中都有逻辑。我不知道UDF中不允许try-catch,直到我尝试重写其中一些不带SP的代码。