Wie kann ich eine Datums- / Uhrzeitangabe in SQL Server kürzen?

280

Wie kann ein Datums- / Uhrzeitwert in SQL Server 2008 am besten abgeschnitten werden (um Stunden, Minuten und Sekunden zu entfernen)?

Beispielsweise:

declare @SomeDate datetime = '2009-05-28 16:30:22'
select trunc_date(@SomeDate)

-----------------------
2009-05-28 00:00:00.000
Julius Caesar
quelle

Antworten:

494

Dies sammelt auch einige Jahre später häufig zusätzliche Stimmen, und deshalb muss ich es für moderne Versionen von SQL Server aktualisieren. Für SQL Server 2008 und höher ist es einfach:

cast(getDate() As Date)

Beachten Sie, dass die letzten drei Absätze im unteren Bereich weiterhin gelten und Sie häufig einen Schritt zurücktreten müssen, um die Besetzung überhaupt zu vermeiden.

Es gibt aber auch andere Möglichkeiten, dies zu erreichen. Hier sind die häufigsten.

Der richtige Weg (neu seit SQL Server 2008):

cast(getdate() As Date)

Der richtige Weg (alt):

dateadd(dd, datediff(dd,0, getDate()), 0)

Dies ist jetzt älter, aber es ist immer noch wissenswert, da es sich auch leicht an andere Zeitpunkte anpassen lässt, wie den ersten Moment des Monats, der Minute, der Stunde oder des Jahres.

Auf diese korrekte Weise werden dokumentierte Funktionen verwendet, die Teil des Ansi-Standards sind und garantiert funktionieren, aber etwas langsamer sein können. Es funktioniert, indem ermittelt wird, wie viele Tage von Tag 0 bis zum aktuellen Tag vorhanden sind, und so viele Tage zurück zu Tag 0 hinzugefügt werden. Dies funktioniert unabhängig davon, wie Ihre Datums- und Uhrzeitangabe gespeichert ist und welches Gebietsschema Sie haben.

Der schnelle Weg:

cast(floor(cast(getdate() as float)) as datetime)

Dies funktioniert, weil datetime-Spalten als 8-Byte-Binärwerte gespeichert werden. Wirf sie in Float um, lege sie auf den Boden, um den Bruch zu entfernen, und der Zeitanteil der Werte ist weg, wenn du sie auf datetime zurückwirfst. Es ist alles nur ein bisschen verschoben ohne komplizierte Logik und es ist sehr schnell.

Beachten Sie, dass dies von einem Implementierungsdetail abhängt, das Microsoft jederzeit ändern kann, selbst bei einem automatischen Service-Update. Es ist auch nicht sehr tragbar. In der Praxis ist es sehr unwahrscheinlich, dass sich diese Implementierung bald ändert. Es ist jedoch wichtig, sich der Gefahr bewusst zu sein, wenn Sie sie verwenden. Und jetzt, da wir die Möglichkeit haben, als Datum zu besetzen, ist dies selten notwendig.

Der falsche Weg:

cast(convert(char(11), getdate(), 113) as datetime)

Der falsche Weg funktioniert durch Konvertieren in eine Zeichenfolge, Abschneiden der Zeichenfolge und Zurückkonvertieren in eine Datums- / Uhrzeitangabe. Es ist aus zwei Gründen falsch : 1) es funktioniert möglicherweise nicht in allen Regionen und 2) es geht um den langsamsten Weg, dies zu tun ... und nicht nur ein wenig; Es ist wie eine Größenordnung oder zwei langsamer als die anderen Optionen.


Update Dies hat in letzter Zeit einige Stimmen erhalten, und deshalb möchte ich hinzufügen, dass ich seit dem Posten einige ziemlich solide Beweise dafür gesehen habe, dass SQL Server den Leistungsunterschied zwischen "korrektem" und "schnellem" Weg optimieren wird Das heißt, Sie sollten jetzt die erstere bevorzugen.

In beiden Fällen möchten Sie Ihre Abfragen schreiben, um zu vermeiden, dass dies überhaupt erforderlich ist . Es ist sehr selten, dass Sie diese Arbeit an der Datenbank ausführen sollten.

In den meisten Fällen ist die Datenbank bereits Ihr Engpass. Es ist im Allgemeinen der Server, auf dem das Hinzufügen von Hardware für Leistungsverbesserungen am teuersten ist und auf dem es am schwierigsten ist, diese Ergänzungen richtig zu machen (Sie müssen beispielsweise die Festplatten mit dem Speicher in Einklang bringen). Es ist auch am schwierigsten, sowohl technisch als auch geschäftlich nach außen zu skalieren. Es ist technisch viel einfacher, einen Web- oder Anwendungsserver als einen Datenbankserver hinzuzufügen, und selbst wenn dies falsch wäre, zahlen Sie nicht mehr als 20.000 USD pro Serverlizenz für IIS oder Apache.

Der Punkt, den ich versuche, ist, dass Sie diese Arbeit, wann immer möglich, auf Anwendungsebene ausführen sollten. Das einzige Mal, dass Sie jemals feststellen sollten, dass Sie eine Datums- / Uhrzeitangabe auf SQL Server abschneiden, ist, wenn Sie nach Tag gruppieren müssen, und selbst dann sollten Sie wahrscheinlich eine zusätzliche Spalte als berechnete Spalte einrichten, die zum Zeitpunkt des Einfügens / Aktualisierens verwaltet oder verwaltet wird in der Anwendungslogik. Holen Sie sich diese indexbrechende, CPU-schwere Arbeit aus Ihrer Datenbank.

Joel Coehoorn
quelle
6
Der "schnelle Weg" ist immer noch der schnellste Weg für SQL 2008 nach einem Benchmark, den ich gerade durchgeführt habe
Sam Saffron
3
Zu Ihrer Information : stackoverflow.com/q/1177449/27535 und stackoverflow.com/q/133081/27535 Das Datum / Datum "gewinnt ...". Für eine einzelne Variable, wen interessiert das natürlich, und man hofft, dass Sie Spalten oder dergleichen über eine Million Zeilen berechnet haben :-)
gbn
9
Dieser "richtige" Weg funktioniert nur aus Versehen. Die Art und Weise, wie es geschrieben wird, ist so, als ob die Syntax für DateAdd (Intervall, Datum, Inkrement) wäre, ist es aber nicht. Es ist (Intervall, Inkrement, Datum). Ich bin darauf gestoßen, als ich versucht habe, ein Datum auf den ersten des Monats zu kürzen: SELECT DATEADD (m, 0, DATEDIFF (m, 0, GETDATE ())) funktioniert nicht, aber SELECT DATEADD (m, DATEDIFF (m, 0, GETDATE ()), 0). Zumindest sehe ich das in 2008R2.
Kelly Cline
1
@ Kelly in 2008R2, warum nicht einfach cast(getdate() as date)?
Joel Coehoorn
2
Sie alle arbeiten an einer Datums- / Uhrzeitspalte. getdate()Hier finden Sie einen Ersatz für jede Datums- / Uhrzeitquelle, die Sie möglicherweise haben.
Joel Coehoorn
44

Nur für SQL Server 2008

CAST(@SomeDateTime AS Date) 

Wenn Sie möchten, setzen Sie es dann auf datetime zurück

CAST(CAST(@SomeDateTime AS Date) As datetime)
DJ.
quelle
Guter Punkt: Ich bin immer noch auf 2005 und für 2008 ist dies wahrscheinlich der neue "richtige" Weg und kann sogar der Leistung des "schnellen" Weges entsprechen.
Joel Coehoorn
1
Die Leistung dieses neuen Weges ist noch schneller als der "schnelle" Weg.
ErikE
21

Nur um eine vollständigere Antwort zu erhalten, finden Sie hier eine Arbeitsweise zum Abschneiden auf Datumsangaben nach unten und einschließlich Minuten (durch GETDATE()das zu kürzende Datum ersetzen ).

Dies unterscheidet sich von der akzeptierten Antwort darin, dass Sie nicht nur dd(Tage), sondern alle Datumsangaben verwenden können (siehe hier ):

dateadd(minute, datediff(minute, 0, GETDATE()), 0)

Beachten Sie, dass im obigen Ausdruck das 0ein konstantes Datum am Anfang eines Jahres ist (1900-01-01). Wenn Sie auf kleinere Teile zuschneiden müssen, z. B. auf Sekunden oder Millisekunden, müssen Sie ein konstantes Datum verwenden, das näher am zu schneidenden Datum liegt, um einen Überlauf zu vermeiden.

Lucero
quelle
1
Das war ungeheuer hilfreich. Ich suchte überall nach einer Möglichkeit, die Datums- und Uhrzeitangabe an einem Ort zu kürzen, der niedriger als der ganze Tag ist.
Michael - Wo ist Clay Shirky
1
@ Michael, danke für das Feedback, gut zu wissen, dass es dir geholfen hat!
Lucero
1
+1 dies sollte mehr positive Stimmen haben, es ist eine großartige Antwort, die die ausgewählte Antwort erweitert.
jtate
1
Nur damit das Internet weiß, müssen Sie sich nicht auf vollständige Datumsabschnitte beschränken. Hier ist ein Beispiel für 15-Minuten-Intervalle unter Verwendung der Ganzzahldivision:dateadd(minute, datediff(minute, 0, GETDATE()) / 15 * 15, 0)
Michael - Wo ist Clay Shirky
7

Das Snippet, das ich im Web gefunden habe, als ich das tun musste, war:

 dateadd(dd,0, datediff(dd,0, YOURDATE))
 e.g.
 dateadd(dd,0, datediff(dd,0, getDate()))
Tom Ritter
quelle
Ich bin auf 2005, aber ich dachte, 2008 hätte eine neue Funktion dafür?
KM.
2
Ordentlich! Ich hätte darauf zurückgegriffen, die Datumsteile aufzuteilen und sie mithilfe der Zeichenfolgenbehandlung wieder zusammenzusetzen. Möglicherweise nicht relevant, aber SQL2008 hat einen reinen Datentyp nur mit Datum ohne Zeitelement.
Frans
1
Und beachten Sie, dass Sie die DateAdd-Operanden verwechselt haben DateAdd(dd, DateDiff(...), 0). Dies kann Sie beißen, wenn Sie nicht vorsichtig sind.
ErikE
1

In SQl 2005 könnte Ihre Funktion trunc_date so geschrieben werden.

(1)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
    CAST(FLOOR( CAST( @date AS FLOAT ) )AS DATETIME)
END

Die erste Methode ist viel sauberer. Es werden nur 3 Methodenaufrufe verwendet, einschließlich des endgültigen CAST (), und es wird keine Zeichenfolgenverkettung durchgeführt, was ein automatisches Plus ist. Darüber hinaus gibt es hier keine großen Typabgüsse. Wenn Sie sich vorstellen können, dass Datums- / Zeitstempel dargestellt werden können, ist die Konvertierung von Datumsangaben in Zahlen und zurück in Datumsangaben ein ziemlich einfacher Vorgang.

(2)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
      SELECT CONVERT(varchar, @date,112)
END

Wenn Sie sich Sorgen über die Implementierung der Datumsangaben durch Microsoft machen, sind (2) oder (3) möglicherweise in Ordnung.

(3)

CREATE FUNCTION trunc_date(@date DATETIME)
RETURNS DATETIME
AS
BEGIN
SELECT CAST((STR( YEAR( @date ) ) + '/' +STR( MONTH( @date ) ) + '/' +STR( DAY(@date ) )
) AS DATETIME
END

Drittens die ausführlichere Methode. Dazu müssen Sie das Datum in seine Teile für Jahr, Monat und Tag aufteilen, diese im Format "JJJJ / MM / TT" zusammenstellen und dann auf ein Datum zurücksetzen. Diese Methode umfasst 7 Methodenaufrufe, einschließlich des endgültigen CAST (), ganz zu schweigen von der Verkettung von Zeichenfolgen.

AlejandroR
quelle
1
CONVERT(DATE, <yourdatetime>) or CONVERT(DATE, GetDate()) or CONVERT(DATE, CURRENT_TIMESTAMP)
Dean
quelle
0

Für diejenigen unter Ihnen, die hierher gekommen sind, um ein DATETIME-Feld auf weniger als einen ganzen Tag zu kürzen, beispielsweise jede Minute, können Sie Folgendes verwenden:

SELECT CAST(FLOOR(CAST(GETDATE() AS FLOAT)) + (FLOOR((CAST(GETDATE() AS FLOAT) - FLOOR(CAST(GETDATE() AS FLOAT))) * 1440.0) + (3.0/86400000.0)) / 1440.0 AS DATETIME)

Wenn also heute 2010-11-26 14:54:43.123wäre, würde dies zurückkehren 2010-11-26 14:54:00.000.

Ersetzen Sie 1440.0 durch die Anzahl der Intervalle pro Tag, um das Intervall zu ändern, in dem es ausgeführt wird. Beispiel:

24hrs          =   24.0  (for every hour)
24hrs / 0.5hrs =   48.0  (for every half hour)
24hrs / (1/60) = 1440.0  (for every minute)

(Setzen Sie immer ein .0am Ende, um implizit auf einen Schwimmer zu werfen.)


Für diejenigen unter Ihnen, die sich fragen, wozu das (3.0/86400000)in meiner Berechnung gut ist, scheint SQL Server 2005 nicht FLOATzu DATETIMEgenau zu wirken, daher werden 3 Millisekunden hinzugefügt, bevor der Bodenbelag erstellt wird.

BG100
quelle
1
Seien Sie jedoch vorsichtig mit Rundungsfehlern aufgrund von Gleitkomma-Genauigkeitsgrenzen ... auch dies funktioniert nicht mit dem datetime2Datentyp.
Lucero
Für Hour funktioniert auch SELECT DATEADD (Stunde, DATEDIFF (Stunde, 0, GETDATE ()), 0). Minute auch, aber Sekunde führt zu einem Überlauf.
Kelly Cline
Das Casting in Float und zurück zur Datumszeit funktioniert nicht richtig .
ErikE
0

Diese Abfrage sollte ein Ergebnis liefern, das dem trunc(sysdate)von Oracle entspricht.

SELECT  * 
FROM    your_table
WHERE   CONVERT(varchar(12), your_column_name, 101)
      = CONVERT(varchar(12), GETDATE(), 101)

Hoffe das hilft!

Sandeep Gaadhe
quelle
0

Sie können das Datum auch using Substringaus der Variablen datetime extrahieren. Wenn Sie auf datetime zurücksetzen, wird der Zeitteil ignoriert.

declare @SomeDate datetime = '2009-05-28 16:30:22'
SELECT cast(substring(convert(varchar(12),@SomeDate,111),0,12) as Datetime) 

Sie können auch auf Teile der datetime-Variablen zugreifen und diese zu einem abgeschnittenen Konstruktdatum zusammenführen.

SELECT cast(DATENAME(year, @Somedate) + '-' + 
       Convert(varchar(2),DATEPART(month, @Somedate)) + '-' +
       DATENAME(day, @Somedate) 
       as datetime)
NeverHopeless
quelle
0

Orakel:

TRUNC(SYSDATE, 'MONTH')

SQL Server:

DATEADD(DAY, - DATEPART(DAY, DateField) + 1, DateField)

Könnte auch zum Abschneiden von Minuten oder Stunden von einem Datum verwendet werden.

Markus
quelle
0

Sie können dies einfach tun (SQL 2008):

deklariere @SomeDate date = getdate ()

select @SomeDate

2009-05-28

Hagai Danenberg-Lerner
quelle