Original von Tibor Karaszi; deutsche Übersetzung von Frank Kalis
Überblick
Zweck dieses Artikels ist es zu erklären, wie die Datetime Datentypen in SQL Server arbeiten; einschliesslich häufig auftretender Stolperfallen und allgemeinen Empfehlungen im Umgang mit ihnen.
Angenommen, wir haben die Aufgabe eine Urlaubsliste zu generieren, die zur Urlaubsplanung verwendet werden soll. Die Basistabelle ist recht einfach aufgebaut:
Heute ist der 05.12.2007. Was muss ich nun machen, um den letzten Sonntag davor in T-SQL zu ermitteln?
Ein Blick in den Kalendar zeigt, daß als Ergebnis der 02.12.2007 herauskommen muss.
DECLARE @seconds INT
DECLARE @hours INT
DECLARE @minutes INT
--
SET @seconds = 3661
SET @hours = FLOOR(@seconds/(60*60))
SET @minutes = FLOOR((@seconds - (@hours*3600))/60)
--
SELECT
RIGHT('0' + CONVERT(VARCHAR(2), @hours), 2) +
':' +
RIGHT('0' + CONVERT(VARCHAR(2), @minutes), 2)
-----
01:01
(1 row(s) affected)
Man könnte allerdings auch:
SET @secs = 3661
SELECT CONVERT(VARCHAR(5), DATEADD(SECOND, @secs, '00:00'), 108)
-----
01:01
(1 row(s) affected)
verwenden.
Da sitzt man abends völlig entspannt am Schreibtisch, blättert in alten Unterlagen aus der Studienzeit weil man sich an gewisse mathematische Zusammenhänge nicht mehr so direkt aus dem Kopf erinnern kann, und - zack - stolpert man über Integer Arithmetik. Die (durchaus verworrene) Assoziationskette zu SQL Server und DATETIMEs führt jedenfalls dann dazu, daß das Mathebuch erst einmal Mathebuch ist und bleibt und wir einen Selbstversuch in Datumsarithmetik unternehmen.
Die Anforderung, Auswertungen zu erstellen, die die Daten auf stündlicher Basis aufbereiten und auswerten, findet sich in vielen Bereichen. Zum Beispiel, Anzahl der Telefonate pro Mitarbeiter pro Stunde, Durchschnittswerte irgendwelcher Meßwerte pro Stunde usw... Hier ist eine einfache, aber effektive Methode, solche Anforderungen umzusetzen:
Angenommen man hat Integer Daten in der Form 20050623 vorliegen, die ein Datum repräsentieren sollen und deshalb in einen DateTime Wert konvertiert werden sollen. Wie schön einfach wäre es nun, wenn eine direkte Konvertierung funktionieren würde:
DECLARE @i INT
SET @i = 20050623
SELECT CAST(@i AS DATETIME)
Server: Msg 8115, Level 16, State 2, Line 3
Arithmetic overflow error converting expression to data type datetime.
Ein Weg nun doch noch zum gewünschten Ergebnis zu kommen, ist die Konvertierung zuerst in eine Zeichenfolge und dann anschließend in DateTime. Etwas so:
SELECT CAST(CAST(@i AS CHAR(8)) AS DATETIME)
------------------------------------------------------
2005-06-23 00:00:00.000
(1 row(s) affected)
Funktioniert einwandfrei!
Nun kann man sich aber noch einige Tastaturanschläge sparen, wenn man sich eines kleinen Tricks bedient:
SELECT CAST(LTRIM(@i) AS DATETIME)
------------------------------------------------------
2005-06-23 00:00:00.000
(1 row(s) affected)
Funktioniert ebenfalls einwandfrei. Aber warum?
Der "Trick" dabei ist, daß man sich den Rückgabetyp mancher Stringfunktionen zunutze macht und diese Funktionen die Konvertierung in eine Zeichenfolge durchführen läßt. So lassen sich, zum Beispiel, LTRIM(), RTRIM() und STR(@i,8) in obiges Statement einbauen und all produzieren den gewünschten Effekt.
Vorweggeschickt mag man durchaus darüber diskutieren, ob eine eigene Funktion zur Ermittlung eines Schaltjahres im SQL Server zwingend notwendig ist, da die meisten Client Sprachen bereits mit ausgefeilten hochoptimierten Datumsbibliotheken ausgestattet sind und daher deutlich bessere Performance bieten sollten als pseudokompiliertes T-SQL, aber ehrlich gesagt geht es mir jetzt mehr darum, einen Weg zu zeigen, wie eine T-SQL basierte Lösung für dieses Problem aussehen könnte. Und die Entscheidung, ob die vorgeschlagene Lösung eingesetzt wird, mag jeder Leser mit sich selber und seinen Anforderungen ausmachen. :-)