Funktion zum Empfangen einer Zeicheneingabe und zum Zurückgeben des Datumsformats (mit falscher Eingabe)

9

Ich muss eine Funktion schreiben, um ein Zeichenfolgenzeichen zu erhalten und das Datumsformat zurückzugeben. Zum Beispiel ist die Eingabe 20120101 und ich brauche diese 2012-01-01. Das Problem ist, dass möglicherweise falsche Eingaben wie diese "2012ABCD" vorliegen. In diesem Fall möchte ich, dass die Funktion ein festes Datum wie 2020-01-01 zurückgibt. Was ich bisher geschrieben habe ist:

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

Dies funktioniert nicht und ich weiß nur nicht, wie ich mit dem zweiten Teil umgehen soll (wenn die Eingabe falsch ist).

Pantea Tourang
quelle
1
Ich kann empfehlen, dass Sie "Abfragen von Daten mit Transact-SQL" lesen. Wenn Sie viel SQL-Programmierung durchführen, werden Ihnen in diesem Buch die Grundlagen zum Codieren solcher Dinge vermittelt. amazon.com/Exam-70-761-Querying-Data-Transact-SQL-ebook/dp/…
Tony Hinkle
1
Möchten Sie das yyyymmddFormat streng analysieren ?
Dan Guzman

Antworten:

9

Unter SQL Server 2012 und höher können Sie mit TRY_CONVERT prüfen, ob die Eingabe konvertiert werden kann. Wenn dies nicht möglich ist, wird ein NULL-Wert zurückgegeben. Anschließend können Sie eine COALESCE ausführen, um entweder den konvertierten Wert oder das feste Datum abzurufen.

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

Sie können auch einen TRY CATCHBlock verwenden und das feste Datum im CATCHBlock zurückgeben. Es wird jedoch empfohlen, TRY_CONVERT zu verwenden, damit SQL Server keinen Fehler behandeln muss, da dies mehr Zeit und Ressourcen erfordert.

Eine Funktion für diesen Codetyp verursacht mehr Overhead als die Verwendung derselben Logik in der Abfrage. Wenn sie also mehrmals pro Sekunde aufgerufen wird, können Sie mithilfe einer Funktion erhebliche Ressourcen verbrauchen. Ich verstehe, dass dies aus zahlreichen Codeteilen aufgerufen werden kann, so dass der Wunsch besteht, es zu einer Funktion zu machen, falls das Standarddatum geändert werden muss - dann werden keine kompilierten Codeänderungen vorgenommen und diese Funktion nur aktualisiert.

Wenn dieser Code häufig ausgeführt wird, sollten Sie andere Optionen in Betracht ziehen, die eine bessere Leistung als eine benutzerdefinierte Funktion bieten. In Salomos Antwort finden Sie eine Übersicht über Ihre Optionen und eine weitere Erklärung, warum Sie eine über die andere wählen könnten.

Im Folgenden wird beispielsweise dieselbe Logik gezeigt, die als Inline-Tabellenwertfunktion implementiert ist, die verwendet werden muss, CROSS APPLYwenn kein statischer Wert angegeben wird, aber eine viel bessere Leistung als eine skalare UDF aufweist:

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
quelle
6
Aber ich würde einfach TRY_CONVERT in der Abfrage verwenden und die ganze Idee verwerfen, eine ineffiziente skalare UDF für diese zu verwenden ...
Aaron Bertrand
2
Ich kümmere mich nicht wirklich um die Wiederholungspunkte, deshalb sage ich es nicht, weil ich solche verloren habe, aber die Community profitiert nicht davon, eine offensichtlich richtige Antwort herunterzustimmen. Schreiben Sie eine Antwort, bearbeiten Sie meine oder hinterlassen Sie einen Kommentar zu den Änderungen, die geändert werden müssen. OP hat nach einer Funktion gefragt, und mir ist klar, dass dies möglicherweise nicht die beste Lösung ist, aber es ist die Lösung, die angefordert wurde.
Tony Hinkle
3
Tony: Ich habe nicht abgelehnt, aber ich stimme mit Sicherheit zu, dass jemand nicht abstimmen sollte, ohne entweder die Begründung in einem Kommentar anzugeben oder einen vorhandenen Kommentar, der seine Begründung enthält, zu stimmen. Das heißt: 1) Es gibt keinen FINALLYBlock in T-SQL (ich denke, Sie meinten CATCH). 2) Sie sollten wahrscheinlich erwähnen, dass dies TRY_CONVERTim Jahr 2012 begonnen hat (einige Leute stecken vor SQL Server 2012 fest). 3) Haben Sie eine Inline-TVF in Betracht gezogen? Diese haben nicht die gleichen Leistungsprobleme wie skalare UDFs.
Solomon Rutzky
1
@ TonyHinkle Vielen Dank für diese Änderungen und für den Verweis auf meine SO-Antwort :). Trotzdem bin ich mir nicht sicher, wie viele Leser den Sprung von der UDF-Logik und dem Lesen, dass eine Inline-TVF besser ist, zur erfolgreichen Implementierung der iTVF schaffen werden. Also habe ich es am Ende Ihrer Antwort hinzugefügt.
Solomon Rutzky
1
@SolomonRutzky Danke. Ich bin nicht wirklich ein SQL-Entwickler, also ist das immer noch über meinem Kopf. Vielleicht sollte ich so etwas nicht beantworten, aber es ist eine enorme Lernmöglichkeit.
Tony Hinkle