【发布时间】:2011-01-01 14:30:18
【问题描述】:
为什么 SQL Server 不支持 UDF 中的 TRY-CATCH 块?
如果我们谈论的是主要用于计算和对话的标量 UDF,那么这个块应该被大量使用,但我们没有。
另外,您对此使用了哪些解决方法?
【问题讨论】:
标签: tsql user-defined-functions
为什么 SQL Server 不支持 UDF 中的 TRY-CATCH 块?
如果我们谈论的是主要用于计算和对话的标量 UDF,那么这个块应该被大量使用,但我们没有。
另外,您对此使用了哪些解决方法?
【问题讨论】:
标签: tsql user-defined-functions
使用 SQLServer 2012,您可以尝试exec sp_your_procedure_with_try_catch,它对我有用。
其实我的几个触发器都有一键SP的逻辑。我不知道 UDF 中不允许 try-catch,直到我尝试在没有 SP 的情况下重写其中一些。
【讨论】:
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 行无效使用 a 副作用运算符“RAISERROR” 在函数中。
如果认为引发错误会改变数据库状态,那么捕获和处理可能也是如此。我承认,这没什么好解释的。
不过,实际上,最好还是让调用者决定如何处理错误。假设你写了一个这样的函数:
create function dbo.divide (@x int, @y int)
returns float
as
begin
return @x / cast(@y as float)
end
您将如何处理应用程序为@y 传递零的情况?如果你捕捉到除以零异常,你接下来要做什么?你可以从对调用者有意义的函数返回什么值,记住你可能甚至不知道哪个应用程序正在调用你的函数?
您可能会考虑返回 NULL,但使用您的函数的应用程序开发人员会同意吗?他们所有的应用程序是否都认为除以零错误具有相同的影响或重要性?更不用说某些地方的 NULL 可以完全改变查询的结果,可能是应用程序开发人员根本不想要的方式。
如果您是唯一的开发人员,也许这不是问题,但随着更多的人,它很快就会成为一个问题。
【讨论】:
可能是因为开销太大 - 标量函数可以作为选择的一部分在列上调用,因此被调用数千次。如果允许 try/catch 有合理的开销,它会大大减慢它。
【讨论】:
作为一种解决方法,我会在存储过程中从 TRY/CATCH 调用 UDF。
【讨论】: