fonction pour recevoir une entrée de caractères et retourner le format de la date (avec une entrée incorrecte)

9

J'ai besoin d'écrire une fonction pour recevoir un caractère de chaîne et retourner le format de date. Par exemple, l'entrée est 20120101 et j'ai besoin de ce 2012-01-01. Le problème est qu'il peut y avoir des entrées incorrectes comme celle-ci "2012ABCD". Dans ce cas, je souhaite que la fonction renvoie une date fixe telle que 2020-01-01. Ce que j'ai écrit jusqu'à présent, c'est:

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

Cela ne fonctionne pas et je ne sais tout simplement pas comment gérer la deuxième partie (lorsque l'entrée est incorrecte).

Pantea Tourang
la source
1
Je pourrais vous recommander de lire "Interroger des données avec Transact-SQL". Si vous effectuez beaucoup de programmation SQL, ce livre vous apprendra les bases de la programmation de choses comme celle-ci. amazon.com/Exam-70-761-Querying-Data-Transact-SQL-ebook/dp/…
Tony Hinkle
1
Voulez-vous une analyse stricte du yyyymmddformat?
Dan Guzman

Réponses:

9

Sur SQL Server 2012 et versions ultérieures, vous pouvez utiliser TRY_CONVERT pour vérifier si l'entrée peut être convertie. Si ce n'est pas le cas, une valeur NULL est renvoyée, vous pouvez alors faire un COALESCE pour obtenir la valeur convertie ou la date fixe.

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

Vous pouvez également utiliser un TRY CATCHbloc et renvoyer la date fixe dans le CATCHbloc, mais il est recommandé d'utiliser TRY_CONVERT afin que SQL Server n'ait pas à gérer une erreur car cela nécessite plus de temps et de ressources.

Une fonction pour ce type de code entraînera plus de surcharge que la simple utilisation de la même logique dans la requête, donc si elle est appelée plusieurs fois par seconde, vous risquez de consommer des ressources importantes en utilisant une fonction pour elle. Je comprends que cela peut être appelé à partir de nombreux morceaux de code, il y a donc un désir d'en faire une fonction au cas où la date par défaut devrait être changée - alors ce n'est pas un changement de code compilé et il suffit de mettre à jour cette fonction.

Si ce code va être exécuté beaucoup, vous devriez considérer d'autres options qui fourniront de meilleures performances qu'une fonction définie par l'utilisateur. Veuillez consulter la réponse de Salomon pour un aperçu de vos options et une explication supplémentaire de la raison pour laquelle vous pouvez choisir l'une plutôt que l'autre.

Par exemple, ce qui suit montre la même logique implémentée en tant que fonction de valeur de table en ligne, qui doit être utilisée avec CROSS APPLYsi elle n'est pas fournie avec une valeur statique, mais fonctionne bien mieux qu'une UDF scalaire:

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
la source
6
Mais je voudrais juste utiliser TRY_CONVERT dans la requête et rejeter l'idée d'utiliser un UDF scalaire inefficace pour cela ...
Aaron Bertrand
2
Je ne me soucie pas vraiment des points de représentant, donc je ne le dis pas en raison de la perte de tels points, mais la communauté ne bénéficie pas du vote négatif une réponse évidemment correcte. Au lieu de voter en aval, écrivez une réponse, modifiez la mienne ou laissez un commentaire sur ce qui doit être changé. OP a demandé une fonction, et je me rends compte que ce n'est peut-être pas la meilleure solution, mais c'est la solution qui a été demandée.
Tony Hinkle
3
Tony: Je n'ai pas voté contre, mais je suis certainement d'accord que quelqu'un ne devrait pas voter contre sans fournir le raisonnement dans un commentaire, ou voter contre un commentaire existant qui inclut leur raisonnement. Cela dit: 1) il n'y a pas de FINALLYbloc dans T-SQL (je pense que vous vouliez dire CATCH). 2) vous devriez probablement mentionner que cela a TRY_CONVERTcommencé en 2012 (certaines personnes sont bloquées avant SQL Server 2012). 3) avez-vous envisagé un TVF en ligne? Ceux-ci n'ont pas les mêmes problèmes de performances que les FDU Scalar.
Solomon Rutzky
1
@TonyHinkle Merci d'avoir fait ces modifications et pour la référence à ma réponse SO :). Pourtant, je ne sais pas combien de lecteurs seront en mesure de faire le saut de voir la logique UDF et de lire qu'un TVF en ligne sera meilleur, pour réussir la mise en œuvre de l'iTVV. J'ai donc continué et je l'ai ajouté à la fin de votre réponse.
Solomon Rutzky
1
@SolomonRutzky Merci. Je ne suis pas vraiment un développeur SQL, donc c'est toujours au-dessus de ma tête. Je ne devrais peut-être pas répondre à quelque chose comme ça, mais c'est une formidable opportunité d'apprentissage.
Tony Hinkle