No SQL Server 2012 e posterior, você pode usar TRY_CONVERT para verificar se a entrada pode ser convertida. Se não puder, um valor NULL será retornado; portanto, você poderá executar um COALESCE para obter o valor convertido ou a data fixa.
begin
declare @result date
set @result = COALESCE(TRY_CONVERT(date, @date, 111), '2012-01-01')
return @result
end
Você também pode usar um TRY CATCH
bloco e retornar a data fixa no CATCH
bloco, mas é uma prática recomendada usar TRY_CONVERT para que o SQL Server não precise manipular um erro, pois isso requer mais tempo e recursos.
Uma função para esse tipo de código acarretará mais sobrecarga do que simplesmente usar a mesma lógica na consulta; portanto, se ela for chamada muitas vezes a cada segundo, você poderá consumir recursos significativos usando uma função para ela. Eu entendo que isso pode ser chamado a partir de vários trechos de código, portanto, há um desejo de torná-lo uma função, caso a data padrão precise ser alterada - então não há alterações no código compilado e atualize essa função.
Se esse código for executado muito, considere outras opções que fornecerão melhor desempenho do que uma função definida pelo usuário. Consulte a resposta de Salomão para obter uma visão geral de suas opções e mais explicações sobre por que você pode escolher uma sobre a outra.
Por exemplo, o seguinte mostra a mesma lógica implementada como uma função com valor de tabela embutida, que precisa ser usada CROSS APPLY
se não for fornecida com um valor estático, mas que tem um desempenho muito melhor que uma UDF escalar:
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
*/