我在写SQL Server中的用户定义函数2008年。我知道,功能不能以通常的方式引发错误 - 如果您尝试包括RAISERROR语句SQL回报:
Msg 443, Level 16, State 14, Procedure ..., Line ...
Invalid use of a side-effecting operator 'RAISERROR' within a function.
但事实是,该功能需要一定的投入,这可能是无效的,如果是这样,也没有有意义的值的函数可以返回。 我该怎么办呢?
我当然可以,返回NULL,但它会使用功能来解决这个任何开发人员很困难。 我还可以通过零或类似的东西引起一个部门 - 这会产生错误信息,但一个误导性的。 有什么办法,我可以有我自己的错误消息不知何故报道?
Answer 1:
您可以使用CAST抛出有意义的错误:
create function dbo.throwError()
returns nvarchar(max)
as
begin
return cast('Error happened here.' as int);
end
然后,SQL Server将显示一些帮助信息:
Msg 245, Level 16, State 1, Line 1
Conversion failed when converting the varchar value 'Error happened here.' to data type int.
Answer 2:
惯用的伎俩是给力除以0。这将发出一个错误并中断正在评估函数当前语句。 如果开发人员或支持人员知道这种行为,调查和故障排除的问题是很容易由0错误的划分被理解为一个不同的,不相关的问题的症状。
那么糟糕,因为这看起来从任何角度来看,此刻的SQL函数不幸的是,设计允许没有更好的选择。 使用RAISERROR要绝对函数被允许。
Answer 3:
从弗拉基米尔·科罗廖夫的答案继,成语有条件地抛出一个错误
CREATE FUNCTION [dbo].[Throw]
(
@error NVARCHAR(MAX)
)
RETURNS BIT
AS
BEGIN
RETURN CAST(@error AS INT)
END
GO
DECLARE @error NVARCHAR(MAX)
DECLARE @bit BIT
IF `error condition` SET @error = 'My Error'
ELSE SET @error = '0'
SET @bit = [dbo].[Throw](@error)
Answer 4:
我认为,最彻底的方法是只接受,如果无效的参数传递函数可以返回NULL。 只要在这清楚地记录那么这应该是好吗?
-- =============================================
-- Author: AM
-- Create date: 03/02/2010
-- Description: Returns the appropriate exchange rate
-- based on the input parameters.
-- If the rate cannot be found, returns NULL
-- (RAISEERROR can't be used in UDFs)
-- =============================================
ALTER FUNCTION [dbo].[GetExchangeRate]
(
@CurrencyFrom char(3),
@CurrencyTo char(3),
@OnDate date
)
RETURNS decimal(18,4)
AS
BEGIN
DECLARE @ClosingRate as decimal(18,4)
SELECT TOP 1
@ClosingRate=ClosingRate
FROM
[FactCurrencyRate]
WHERE
FromCurrencyCode=@CurrencyFrom AND
ToCurrencyCode=@CurrencyTo AND
DateID=dbo.DateToIntegerKey(@OnDate)
RETURN @ClosingRate
END
GO
Answer 5:
RAISEERROR
或@@ERROR
在UDF是不允许的。 你可以把UDF成strored程序?
从厄兰Sommarskog的文章在SQL Server错误处理-一个背景 :
用户定义的函数通常被调用作为一组,SELECT,INSERT,UPDATE或DELETE语句的一部分。 我发现的是,如果出现在多语句表值函数或标量函数的错误,则函数的执行被立即中止,所以是功能的一部分的说法。 继续执行下一行,除非错误中止批处理。 在任一情况下,错误@@是0。因此,就没有方法来检测,在从T-SQL函数发生了错误。
该问题不会与内嵌表函数出现,由于内嵌表值函数基本上是一个宏查询处理器糊剂到查询。
您也可以用EXEC语句执行标量函数。 在这种情况下,继续执行如果发生错误,(除非它是分批中止错误)。 @@ ERROR设置,你可以在函数中检查@@ ERROR的值。 它可以是有问题的,虽然错误传达给调用者。
Answer 6:
顶端回答通常是最好的,但对于内联表值函数不起作用。
MikeTeeVee了在他的顶端回答评论了一个解决方案,但它需要使用像MAX聚合函数,它并没有对我的情况很好地工作的。
我搞砸与周围当您需要一个内联表值UDF返回类似选择*而不是聚集的情况下,替代的解决方案。 示例代码解决这种特殊情况如下。 正如有人已经指出了......“哎呀wotta黑客” :)我欢迎这种情况下,任何更好的解决方案!
create table foo (
ID nvarchar(255),
Data nvarchar(255)
)
go
insert into foo (ID, Data) values ('Green Eggs', 'Ham')
go
create function dbo.GetFoo(@aID nvarchar(255)) returns table as return (
select *, 0 as CausesError from foo where ID = @aID
--error checking code is embedded within this union
--when the ID exists, this second selection is empty due to where clause at end
--when ID doesn't exist, invalid cast with case statement conditionally causes an error
--case statement is very hack-y, but this was the only way I could get the code to compile
--for an inline TVF
--simpler approaches were caught at compile time by SQL Server
union
select top 1 *, case
when ((select top 1 ID from foo where ID = @aID) = @aID) then 0
else 'Error in GetFoo() - ID "' + IsNull(@aID, 'null') + '" does not exist'
end
from foo where (not exists (select ID from foo where ID = @aID))
)
go
--this does not cause an error
select * from dbo.GetFoo('Green Eggs')
go
--this does cause an error
select * from dbo.GetFoo('Yellow Eggs')
go
drop function dbo.GetFoo
go
drop table foo
go
Answer 7:
有几个人在问表值函数提高的错误,因为你不能使用“RETURN [无效转换]”之类的东西。 分配无效投给一个变量的作品一样好。
CREATE FUNCTION fn()
RETURNS @T TABLE (Col CHAR)
AS
BEGIN
DECLARE @i INT = CAST('booooom!' AS INT)
RETURN
END
这导致:
消息245,级别16,状态1,行14转换转换VARCHAR值时失败“booooom!” 为int数据类型。
Answer 8:
下davec的回答关于表值函数,我不能发表评论,但在我的愚见,这是更简单的解决方案:
CREATE FUNCTION dbo.ufn_test (@a TINYINT)
RETURNS @returns TABLE(Column1 VARCHAR(10), Value1 TINYINT)
BEGIN
IF @a>50 -- if @a > 50 - raise an error
BEGIN
INSERT INTO @returns (Column1, Value1)
VALUES('error','@a is bigger than 50!') -- reminder Value1 should be TINYINT
END
INSERT INTO @returns (Column1, Value1)
VALUES('Something',@a)
RETURN;
END
SELECT Column1, Value1 FROM dbo.ufn_test(1) -- this is okay
SELECT Column1, Value1 FROM dbo.ufn_test(51) -- this will raise an error
Answer 9:
单程(一个黑客)是具有执行一个无效的动作的功能/存储过程。 例如,下面的伪SQL
create procedure throw_error ( in err_msg varchar(255))
begin
insert into tbl_throw_error (id, msg) values (null, err_msg);
insert into tbl_throw_error (id, msg) values (null, err_msg);
end;
凡在桌子上tbl_throw_error,对列ERR_MSG的唯一约束。 这方面的一个副作用(至少在MySQL),是当它得到备份到应用程序级的异常对象ERR_MSG的值被用作该异常的描述。
我不知道你是否能做到与SQL Server类似的东西,但值得一试。
文章来源: How to report an error from a SQL Server user-defined function