我正在尝试编写一个UDF来将一个guid或与该guid相关联的项目代码的字符串转换为guid:
CREATE FUNCTION fn_user_GetProjectID
(
@Project nvarchar(50)
)
RETURNS uniqueidentifier
AS
BEGIN
declare @ProjectID uniqueidentifier
BEGIN TRY
set @ProjectID = cast(@Project as uniqueidentifier)
END TRY
BEGIN CATCH
set @ProjectID = null
END CATCH
if(@ProjectID is null)
BEGIN
select @ProjectID = ProjectID from Project where projectcode = @Project
END
return @ProjectID
END
如果上面的代码嵌入在我的存储过程中,这样可以正常工作,但是我想用它来创建一个函数,以便我遵循DRY。
当我尝试创建函数时,我得到这样的错误:
Msg 443, Level 16, State 14, Procedure fn_user_GetProjectID, Line 16
Invalid use of side-effecting or time-dependent operator in 'BEGIN TRY' within a function.
有没有人知道如何解决这个错误?
编辑:我知道我不能在函数中使用Try-Catch,我想简化的问题是,有没有办法进行转换,如果转换失败,只返回NULL,而不是错误?
答案 0 :(得分:3)
显然你不能在UDF中使用TRY-CATCH。
根据bug-reporting page for SQL Server:
联机丛书记录了这种行为, 在主题“创建功能 (Transact-SQL)“:”以下内容 语句在函数中有效: [...] Control-of-Flow语句 除了TRY ... CATCH语句。 [...]“
但是他们在2006年为未来带来了希望:
然而,这是一个严重的限制 应该在将来删除 发布。你应该发表一个建议 在这方面,我会 全心全意地投票支持它。
答案 1 :(得分:2)
来自MSDN:
的列或局部变量 uniqueidentifier数据类型可以 初始化为。中的值 以下方式:
使用NEWID功能。
通过转换为字符串常量 在形式 XXXXXXXXXXXX-XXXXXXXX-XXXXXXXXXXXX, 其中每个x是十六进制数字 在0-9或a-f范围内。
例如, 6F9619FF-8B86-D011-B42D-00C04FC964FF 是一个有效的uniqueidentifier值。
您可以使用模式匹配来验证字符串。请注意,这不适用于减少GUID大小的特定编码:
declare @Project nvarchar(50)
declare @ProjectID uniqueidentifier
declare @HexPattern nvarchar(268)
set @HexPattern =
'[A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9]' +
'[A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9]' +
'[A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9]' +
'[A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9][A-F0-9]'
/* Take into account GUID can have curly-brackets or be missing dashes */
/* Note: this will not work for GUIDs that have been specially encoded */
set @Project = '{' + CAST(NEWID() AS VARCHAR(36)) + '}'
select @Project
set @Project = REPLACE(REPLACE(REPLACE(@Project,'{',''),'}',''),'-','')
/* Cast as uniqueid if pattern matches, otherwise return null */
if @Project LIKE @HexPattern
select @ProjectID = CAST(
SUBSTRING(@Project,1,8) + '-' +
SUBSTRING(@Project,9,4) + '-' +
SUBSTRING(@Project,13,4) + '-' +
SUBSTRING(@Project,17,4) + '-' +
SUBSTRING(@Project,21,LEN(@Project)-20)
AS uniqueidentifier)
select @ProjectID
答案 2 :(得分:1)
我知道我不能在函数中使用Try-Catch,我想一个简化的问题是,有没有一种方法可以进行强制转换,如果强制转换失败,它将只返回NULL,错误?
从SQL Server 2012开始,您可以使用TRY_CAST / TRY_CONVERT函数:
如果转换成功,则将值转换为指定的数据类型;否则,返回null。
CREATE FUNCTION fn_user_GetProjectID(@Project nvarchar(50))
RETURNS uniqueidentifier
AS
BEGIN
declare @ProjectID uniqueidentifier = TRY_CAST(@Project as uniqueidentifier);
IF(@ProjectID is null)
BEGIN
select @ProjectID = ProjectID from Project where projectcode = @Project;
END
return @ProjectID;
END
答案 3 :(得分:0)
不确定,但为什么不把它翻转......乍一看我会简化它:
select @ProjectID =
ISNULL((select ProjectID from Project where
projectcode = @Project)
,(cast @Project as uniqueidentifier))
如果这没有提供足够的错误处理,我确信有更好的方法来预先检查演员是否可以在不使用try / catch的情况下工作......
答案 4 :(得分:0)
我的强力方法是创建我自己的ToGuid()函数,验证它是否可以先转换为GUID,否则返回null。它可能不是很快,但它完成了工作,如果它是一个而不是试图在表中查找它可能更快转换guid。编辑:我的意思是赞美这个博客,我得到了这个函数的代码基础:http://jesschadwick.blogspot.com/2007/11/safe-handling-of-uniqueidentifier-in.html
CREATE FUNCTION [dbo].[ToGuid]
(
@input NVARCHAR(MAX)
)
RETURNS uniqueidentifier
AS
BEGIN
DECLARE @isValidGuid BIT;
DECLARE @temp NVARCHAR(MAX);
SET @isValidGuid = 1;
SET @temp = UPPER(LTRIM(RTRIM(REPLACE(REPLACE(REPLACE(@input, '-', ''), '{', ''), '}', ''))));
IF(@temp IS NOT NULL AND LEN(@temp) = 32)
BEGIN
DECLARE @index INT;
SET @index = 1
WHILE (@index <= 32)
BEGIN
IF (SUBSTRING(@temp, @index, 1) IN ('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'A', 'B', 'C', 'D', 'E', 'F'))
BEGIN
SET @index = @index + 1
END
ELSE
BEGIN
SET @isValidGuid = 0
BREAK;
END
END
END
ELSE
BEGIN
SET @isValidGuid = 0
END
DECLARE @ret UNIQUEIDENTIFIER
IF(@isValidGuid = 1)
set @ret = cast(@input AS UNIQUEIDENTIFIER)
ELSE
set @ret = NULL
RETURN @ret
END
如果有更好的答案,我仍然非常感兴趣。
答案 5 :(得分:0)
使用ISNUMERIC函数验证@Project是否为数字。
您的代码应如下所示:
declare @ProjectID uniqueidentifier
set @ProjectID = null
IF ISNUMERIC(@Project) > 0
BEGIN
set @ProjectID = cast(@Project as uniqueidentifier)
END
if(@ProjectID is null)
BEGIN
select @ProjectID = ProjectID from Project where projectcode = @Project
END
return @ProjectID