Я пытаюсь записать UDF для перевода строки, которая является или гуидом или кодом проекта, связанным с тем гуидом в гуид:
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.
У кого-либо есть идея, как я могу обойти эту ошибку?
Править: Я знаю, что не могу использовать Выгоду Попытки в Функции, я предполагаю, упрощенные вопросы были бы, там способ сделать бросок, который просто возвратит ПУСТОЙ УКАЗАТЕЛЬ, если состав исполнителей перестанет работать вместо ошибки?
Из MSDN :
Столбец или локальная переменная Тип данных uniqueidentifier может быть инициализируется значением в следующими способами:
Используя функцию NEWID.
Путем преобразования из строковой константы в виде xxxxxxxx-xxxx-xxxx-xxxx-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
Очевидно, вы не можете использовать TRY-CATCH в UDF.
Согласно этой странице отчетов об ошибках для SQL Server :
Электронная документация документирует это поведение, в теме "СОЗДАТЬ ФУНКЦИЮ (Transact-SQL) ":" следующие утверждения действительны в функции: [...] Операторы управления потоком кроме операторов TRY ... CATCH. [...] "
Но они давали надежду на будущее еще в 2006 году:
Однако это серьезное ограничение это должно быть удалено в будущем выпускать. Вы должны опубликовать предложение в этом отношении, и я буду от всей души голосую за это.
Не уверен, но почему бы не перевернуть все наоборот... на первый взгляд я бы упростил это так:
select @ProjectID =
ISNULL((select ProjectID from Project where
projectcode = @Project)
,(cast @Project as uniqueidentifier))
Если это не обеспечивает достаточной обработки ошибок, я уверен, что есть лучший способ предварительно проверить, что бросок может работать без использования try/catch...
Мой метод перебора заключался в создании собственной функции ToGuid(), которая сначала проверяет, может ли она быть преобразована в GUID, если нет, то возвращает null. Это может быть не очень быстро, но это делает свою работу, и, вероятно, быстрее преобразовать guid, если он один, чем пытаться найти его в таблице. EDIT: Я хотел отдать должное этому блогу, где я взял основу моего кода для этой функции: 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
Мне все еще очень интересно, есть ли лучший ответ, чем этот.