función para recibir una entrada de caracteres y formato de fecha de retorno (con entrada incorrecta)

9

Necesito escribir una función para recibir un carácter de cadena y devolver el formato de fecha. Por ejemplo, la entrada es 20120101 y necesito esta 2012-01-01. El problema es que puede haber algunas entradas incorrectas como esta "2012ABCD". En ese caso, quiero que la función devuelva una fecha fija como 2020-01-01. Lo que he escrito hasta ahora es:

Create Function ReturnDate
(@date varchar(8))

Returns date

  as

    begin
       declare @result date

          set @result = (select convert(date , @date,111))
                if(@@ROWCOUNT>0) return @result
                 else return '2020-01-01'
       return @result
    end

Esto no funciona y simplemente no sé cómo manejar la segunda parte (cuando la entrada es incorrecta).

Pantea Tourang
fuente
1
Podría recomendarle que lea "Consultar datos con Transact-SQL". Si va a hacer mucha programación SQL, este libro le enseñará los conceptos básicos sobre cómo codificar cosas como esta. amazon.com/Exam-70-761-Querying-Data-Transact-SQL-ebook/dp/…
Tony Hinkle
1
¿Desea un análisis estricto del yyyymmddformato?
Dan Guzman

Respuestas:

9

En SQL Server 2012 y versiones posteriores, puede usar TRY_CONVERT para verificar si la entrada se puede convertir. Si no puede, se devuelve un valor NULL para que pueda hacer una COALESCE para obtener el valor convertido o la fecha fija.

begin
   declare @result date
   set @result = COALESCE(TRY_CONVERT(date, @date, 111), '2012-01-01')
   return @result
end

También puede usar un TRY CATCHbloque y devolver la fecha fija en el CATCHbloque, pero es una buena práctica usar TRY_CONVERT para que SQL Server no tenga que manejar un error, ya que requiere más tiempo y recursos.

Una función para este tipo de código generará más sobrecarga que simplemente usar la misma lógica en la consulta, por lo tanto, si se llama muchas veces por segundo, puede absorber un recurso significativo al usar una función para ello. Entiendo que esto se puede invocar desde numerosas piezas de código, por lo que existe el deseo de que sea una función en caso de que la fecha predeterminada deba cambiarse; entonces no se trata de cambios en el código compilado y solo actualice esta función.

Si este código se va a ejecutar mucho, debe considerar otras opciones que proporcionarán un mejor rendimiento que una función definida por el usuario. Consulte la respuesta de Salomón para obtener una descripción general de sus opciones y una explicación más detallada de por qué podría elegir una sobre la otra.

Por ejemplo, a continuación se muestra la misma lógica implementada como una función en línea con valores de tabla, que debe usarse CROSS APPLYsi no se proporciona un valor estático, pero funciona mucho mejor que un 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
*/
Tony Hinkle
fuente
66
Pero simplemente usaría TRY_CONVERT en la consulta y descartaría la idea de usar un UDF escalar ineficiente para esto ...
Aaron Bertrand
2
Realmente no me importan los puntos de representación, así que no lo digo debido a la pérdida de los mismos, pero la comunidad no se beneficia al votar negativamente por una respuesta obviamente correcta. En lugar de votar negativamente, escriba una respuesta, edite la mía o deje un comentario sobre lo que debe cambiarse. OP solicitó una función, y me doy cuenta de que puede que no sea la mejor solución, pero es la solución que se solicitó.
Tony Hinkle
3
Tony: No voté en contra, pero ciertamente estoy de acuerdo en que alguien no debe votar en contra sin dar el razonamiento en un comentario o votar por un comentario existente que incluya su razonamiento. Dicho esto: 1) no hay FINALLYbloque en T-SQL (creo que quisiste decir CATCH). 2) probablemente debería mencionar que TRY_CONVERTcomenzó en 2012 (algunas personas están estancadas antes de SQL Server 2012). 3) ¿ ha considerado un TVF en línea? Esos no tienen los mismos problemas de rendimiento que los UDF escalares.
Solomon Rutzky
1
@TonyHinkle Gracias por hacer esas ediciones, y por la referencia a mi respuesta SO :). Aún así, no estoy seguro de cuántos lectores podrán dar el salto al ver la lógica UDF y leer que un TVF en línea será mejor, para implementar con éxito el iTVF. Entonces, seguí adelante y lo agregué al final de su respuesta.
Solomon Rutzky
1
@SolomonRutzky Gracias. No soy realmente un desarrollador de SQL, así que todavía está por encima de mi cabeza. Tal vez no debería responder algo como esto, pero es una gran oportunidad de aprendizaje.
Tony Hinkle