В SQL Server 2012 и более поздних версиях вы можете использовать TRY_CONVERT, чтобы проверить, можно ли преобразовать входные данные. Если это невозможно, возвращается значение NULL, поэтому вы можете выполнить COALESCE, чтобы получить либо преобразованное значение, либо фиксированную дату.
begin
declare @result date
set @result = COALESCE(TRY_CONVERT(date, @date, 111), '2012-01-01')
return @result
end
Вы также можете использовать TRY CATCH
блок и вернуть фиксированную дату в CATCH
блоке, но рекомендуется использовать TRY_CONVERT, чтобы SQL Server не обрабатывал ошибку, поскольку это требует больше времени и ресурсов.
Функция для этого типа кода будет сопряжена с большими издержками, чем просто использование одной и той же логики в запросе, поэтому, если она вызывается много раз каждую секунду, вы можете потратить значительный ресурс, используя для него функцию. Я понимаю, что это может быть вызвано из множества кусков кода, поэтому есть желание сделать его функцией в случае, если нужно изменить дату по умолчанию - тогда скомпилированный код не изменится, а просто обновите эту функцию.
Если этот код будет выполняться много, вы должны рассмотреть другие варианты, которые обеспечат лучшую производительность, чем пользовательская функция. Пожалуйста, смотрите ответ Соломона для обзора ваших вариантов и дальнейшего объяснения того, почему вы можете выбрать один из других.
Например, ниже показана та же логика, реализованная в виде встроенной табличной функции, которую необходимо использовать, CROSS APPLY
если она не снабжена статическим значением, но работает намного лучше, чем скалярный UDF:
USE [tempdb];
GO
CREATE
OR ALTER -- comment out if using pre-SQL Server 2016 SP1
FUNCTION dbo.ReturnDate (@Date VARCHAR(8))
RETURNS TABLE
AS RETURN
SELECT ISNULL(TRY_CONVERT(DATE, @Date, 111), '2020-01-01') AS [TheDate];
GO
SELECT *
FROM (VALUES (1, '20120101'), (2, '2012ABCD')) tab(ID, Input)
CROSS APPLY dbo.ReturnDate(tab.[Input]) dt
/*
ID Input TheDate
1 20120101 2012-01-01
2 2012ABCD 2020-01-01
*/