Bester Ansatz zum Entfernen des Zeitteils von datetime in SQL Server

514

Welche Methode bietet die beste Leistung beim Entfernen des Zeitanteils aus einem Datums- / Uhrzeitfeld in SQL Server?

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

oder

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

Die zweite Methode sendet in beiden Fällen einige weitere Bytes, dies ist jedoch möglicherweise nicht so wichtig wie die Geschwindigkeit der Konvertierung.

Beide scheinen auch sehr schnell zu sein, aber es kann einen Geschwindigkeitsunterschied geben, wenn es um Hunderttausende oder mehr Zeilen geht?

Ist es auch möglich, dass es noch bessere Methoden gibt, um den Zeitanteil einer Datums- / Uhrzeitangabe in SQL zu entfernen?

Stephen Perelson
quelle
1
Ich habe dies an einer Million Datensätzen in einer meiner Produktionstabellen ausprobiert und konnte in keiner Weise einen genauen Messwert für die Leistung erhalten. Beide Methoden gaben jedoch genau die gleiche Datenmenge zurück.
Stephen Perelson
9
In 18.000.000 Zeilen habe ich Folgendes gefunden (SQL Server 2008): Methode b ist etwa 24% langsamer als Methode a. CAST (FLOOR (CAST (getdate () AS FLOAT)) AS DATETIME) ist 3,5% langsamer als Methode a. Methode a scheint in Bezug auf die Leistung ein Gewinner zu sein. Vielen Dank für die tollen Antworten.
Stephen Perelson
46
Warum zum Teufel hat SQL sowieso keine eingebaute Funktion, um dies zu tun? !!
Gary McGill
10
Der neue Datentyp DATE von SQL 2008 wird dies verarbeiten.
Philip Kelley

Antworten:

558

Streng genommen ist die Methode aam wenigsten ressourcenintensiv:

a) select DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

Bewährt weniger CPU-intensiv bei gleicher Gesamtdauer eine Million Zeilen von jemandem mit viel zu viel Zeit: Die effizienteste Methode in SQL Server, um Datum von Datum + Uhrzeit abzurufen?

Ich habe anderswo einen ähnlichen Test mit ähnlichen Ergebnissen gesehen.

Ich bevorzuge DATEADD / DATEDIFF, weil:

  • varchar unterliegt Sprach- / Datumsformatproblemen.
    Beispiel: Warum ist mein CASE-Ausdruck nicht deterministisch?
  • float ist auf internen Speicher angewiesen
  • Es erstreckt sich auf den ersten Tag des Monats, morgen usw., indem die Basis "0" geändert wird

Bearbeiten, Okt 2011

Für SQL Server 2008+ können Sie CAST zu datedh CAST(getdate() AS date). Oder verwenden Sie einfach den dateDatentyp, damit Sie keine Zeit zum Entfernen haben.

Bearbeiten, Jan 2012

Ein Beispiel dafür, wie flexibel dies ist: Sie müssen nach gerundeten Zeit- oder Datumsangaben in SQL Server berechnen

Bearbeiten, Mai 2012

Verwenden Sie dies nicht in WHERE-Klauseln und dergleichen, ohne darüber nachzudenken: Das Hinzufügen einer Funktion oder eines CAST zu einer Spalte macht die Indexverwendung ungültig. Siehe Nummer 2 hier: http://www.simple-talk.com/sql/t-sql-programming/ten-common-sql-programming-mistakes/

Dies ist ein Beispiel für spätere SQL Server-Optimierungsversionen, die CAST bis heute korrekt verwalten, aber im Allgemeinen ist dies eine schlechte Idee ...

Bearbeiten, September 2018, für datetime2

DECLARE @datetime2value datetime2 = '02180912 11:45' --this is deliberately within datetime2, year 0218
DECLARE @datetime2epoch datetime2 = '19000101'

select DATEADD(dd, DATEDIFF(dd, @datetime2epoch, @datetime2value), @datetime2epoch)
gbn
quelle
3
@ David Sopko für die Bearbeitung im Oktober 2011, dann lautet der Code: Wählen Sie Besetzung (GETDATE () als Datum)
Choco Smith
1
Bei neueren SQL-Versionen wird durch die Verwendung von Datum anstelle von Datum / Uhrzeit die Notwendigkeit vermieden, sich mit Stunden zu befassen. Verwenden Sie das folgende Beispiel: deklarieren Sie noTime date = getdate (), withTime datetime = getdate () wählen Sie @ noTime, @ withTime
ozkary
1
Die Besetzung als Datum ist großartig, wenn Sie nur das Datum benötigen. Allerdings benötigen Sie häufig das aktuelle Datum um Mitternacht, damit Sie weitere Datumsmanipulationen durchführen können. Die DATEDatenzeit ist in Bezug auf Dinge wie dateadd, dateiff und die Interaktion mit anderen Datums- / Zeitdatentypen unangenehm einschränkend. In diesen Fällen DATEADD()regiert der Ansatz König.
Xedni
Dies funktioniert nicht bei jedem Datum. Ich hatte fälschlicherweise 0218statt 2018als das Jahr eingegeben und der DATEDIFFTeil Ihrer Aussage löst eine Ausnahme aus The conversion of a datetime2 data type to a datetime data type resulted in an out-of-range datetime valueVersuchen Sie:select DATEDIFF(dd, 0, convert(datetime2(0), '0218-09-12', 120))
Bernhard Döbler
1
@ BernhardDöbler im Juli 2009, als ich antwortete, "0218" wäre ein gültiges Datum gewesen, also wären Sie nicht so weit gekommen. Außerdem wird die "0" für datetime2 nicht in 19000101 konvertiert. Versuchen Sie diese AuswahlSELECT DATEDIFF(dd, '19000101', convert(datetime2(0), '0218-09-12', 120))
gbn
69

In SQL Server 2008 können Sie Folgendes verwenden:

CONVERT(DATE, getdate(), 101)
Anto Raja Prakash
quelle
13
Das dritte Argument hat absolut keinen Einfluss auf das Ergebnis bei der Konvertierung von a datetimenach a. Daher läuft dateIhre Lösung effektiv auf das hinaus CONVERT(DATE,getdate()), was bereits mehr als einmal vorgeschlagen wurde.
Andriy M
Verwenden Sie einfach CAST(GETDATE() AS DATE)oder streng ANSI, CAST(CURRENT_TIMESTAMP AS DATE)was ich für wertlos halte. Bleib beim ersten.
Ivanzinho
52

Natürlich ist dies ein alter Thread, aber um ihn zu vervollständigen.

Ab SQL 2008 können Sie den Datentyp DATE verwenden, um Folgendes zu tun:

SELECT CONVERT(DATE,GETDATE())
Arjan Fraaij
quelle
21
SELECT CAST(FLOOR(CAST(getdate() AS FLOAT)) AS DATETIME)

... ist laut den Kommentaren unten keine gute Lösung.

Ich würde diese Antwort löschen, aber ich werde sie hier als Gegenbeispiel belassen, da ich denke, dass die Erklärung der Kommentatoren, warum es keine gute Idee ist, immer noch nützlich ist.

Gary McGill
quelle
Siehe die Antwort von GBN, viele haben dies untersucht. DATETIMEs werden NICHT als Floats gespeichert. Durch die Verwendung von DATEADD / DATEDIFF wird die mathematische Manipulation vermieden, die zum CAST zwischen Typen erforderlich ist.
MatBailie
Ich kann akzeptieren, dass Sie aus dem von Ihnen beschriebenen Grund eine Umwandlung von DATETIME in FLOAT vermeiden möchten, aber ist in diesem Fall die implizite Konvertierung von Null in der OP-Option (a) nicht auch ein Problem? Hmmm ... Ich nehme an, in diesem Fall ist es kein FLOAT und der Server ist wahrscheinlich klug genug, um die Zeitinformationen zu verwerfen. OK, ich gebe zu :-)
Gary McGill
Die 0 ist in der Tat eine implizite Konvertierung von einem numerischen Typ (INT würde ich vermuten) in eine DATETIME. Da es sich jedoch um einen konstanten Ausdruck handelt, kann der Optimierer dies zur Kompilierungszeit für gespeicherte Prozeduren tun und muss dies nur einmal tun, um SQL dynamisch auszuführen. Kurz gesagt, es gibt einen einmaligen Overhead dafür, die FLOAT-basierte Abfrage hat den gleichen Overhead für jede Zeile.
MatBailie
Casting to Float ist furchtbar ungenau. Diese Antwort sollte gelöscht werden. Niemand sollte diesen Code verwenden.
usr
3
Ganz zu schweigen davon, dass es nicht sicher ist, auf Float und zurück auf datetime zu setzen - float hat nicht genug Präzision. Daher denke ich, dass es überhaupt nicht zu empfehlen ist. Weitere Informationen finden Sie in diesem Beitrag .
ErikE
17

In SQL Server 2008 gibt es einen DATE-Datentyp (auch einen TIME-Datentyp).

CAST(GetDate() as DATE)

oder

declare @Dt as DATE = GetDate()
Metapher
quelle
Das habe ich benutzt und es hat gut funktioniert. Scheint die einfachste Antwort zu sein. Irgendwelche Nachteile bei der Verwendung in Verbindung mit CONVERT?
Joelmdev
1
CAST und CONVERT sind in ihrer Funktion gleichwertig. Der Unterschied besteht darin, dass CAST Teil des ANSI-Standards ist, während CONVERT spezifisch für T-SQL ist. Verwenden Sie daher nach Möglichkeit CAST.
Troy
@troy Ich benutze CAST, weil ich 3 Tippbuchstaben speichern kann und die Syntax klarer ist als CONVERT. Der ANSI-Standardteil ist wertlos
Ivanzinho
8

Hier ist noch eine Antwort von einer anderen doppelten Frage:

SELECT CAST(CAST(getutcdate() - 0.50000004 AS int) AS datetime) 

Diese magische Zahlenmethode ist etwas schneller als die DATEADD-Methode. (Es sieht aus wie ~ 10%)

Die CPU-Zeit in mehreren Runden von einer Million Datensätzen:

DATEADD   MAGIC FLOAT
500       453
453       360
375       375
406       360

Beachten Sie jedoch, dass diese Zahlen möglicherweise irrelevant sind, da sie bereits SEHR schnell sind. Ohne Rekordsätze von 100.000 oder mehr konnte ich nicht einmal die CPU-Zeit zum Lesen über Null bringen.

In Anbetracht der Tatsache, dass DateAdd für diesen Zweck gedacht und robuster ist, würde ich DateAdd verwenden.

Jeff Fleischbällchen Yang
quelle
1
Das ist schrecklich Ich würde meine Daten niemals so gefährden. Wer weiß, ob dies für alle Datenzeiten korrekt ist , nicht nur für die von Ihnen getesteten.
usr
@usr Oh, es ist richtig, es ist nur eine magische Zahl und sollte aus diesem Grund nicht verwendet werden. Wenn Sie die Richtigkeit überprüfen möchten, füllen Sie einfach alle möglichen Daten für einen Tag in eine Tabelle und überprüfen Sie die Ergebnisse! Weitere Informationen finden Sie auch in diesem Beitrag .
ErikE
@ErikE guter Punkt. Ihre Antwort bietet jedoch die Möglichkeit, '12:00:00.003'die ich für viel besser halte.
usr
6
SELECT CAST(CAST(GETDATE() AS DATE) AS DATETIME)
Byju
quelle
4
Eine gültige Option, ja. Mehr als einmal in diesem Thread vorgeschlagen.
Andriy M
Ehrlich gesagt ist diese Lösung am einfachsten zu lesen. Mein goto
BelgoCanadian
5

Ich mag wirklich:

[date] = CONVERT(VARCHAR(10), GETDATE(), 120)

Der 120Formatcode zwingt das Datum in die Norm ISO 8601:

'YYYY-MM-DD' or '2017-01-09'

Super einfach in dplyr ( R) und pandas ( Python) zu verwenden!

Emehex
quelle
3

IN ACHT NEHMEN!

Methode a) und b) haben NICHT immer die gleiche Leistung!

select DATEADD(dd, DATEDIFF(dd, 0, '2013-12-31 23:59:59.999'), 0)

Ausgabe: 2014-01-01 00:00:00.000

select cast(convert(char(11), '2013-12-31 23:59:59.999', 113) as datetime)

Ausgabe: 2013-12-31 00:00:00.000

(Getestet auf MS SQL Server 2005 und 2008 R2)

BEARBEITEN: Laut Adams Kommentar kann dies nicht passieren, wenn Sie den Datumswert aus der Tabelle lesen, aber es kann passieren, wenn Sie Ihren Datumswert als Literal angeben (Beispiel: als Parameter einer gespeicherten Prozedur, die über ADO.NET aufgerufen wird).

broslav
quelle
1
.999 kann nicht in SQL Server in einer DATETIMESpalte gespeichert werden . Der höchste verfügbare Wert ist .997. Von: msdn.microsoft.com/en-us/library/ms187819.aspx sehen Sie, dass die Werte gerundet sind, um den tausendsten Platz auf 0, 3 oder 7 zu haben. Das OP wird nicht angezeigt den Wert aus Ihrem Test in ihren Tabellen.
Adam Wenger
Du hast Recht. Ich wollte dies nicht als Antwort auf die OP-Frage posten, sondern als Kommentar für andere, aber ich hatte nur 11 Reputationspunkte und 15 werden zum Kommentieren benötigt.
Broslav
In Ihrem ersten Snippet wird die Zeichenfolgenkonstante implizit in eine Datums- / Uhrzeitkonstante konvertiert, in Ihrem zweiten bleibt sie eine Zeichenfolge (und die 113 wird einfach ignoriert).
Andriy M
2

Entfernen Sie zunächst die Zeit für Einfügungen / Aktualisierungen. Bei der On-the-Fly-Konvertierung kann eine benutzerdefinierte Funktion in Bezug auf die Wartbarkeit nichts übertreffen:

select date_only(dd)

Die Implementierung von date_onlykann beliebig sein - jetzt ist sie abstrahiert und das Aufrufen von Code ist viel sauberer.

Anton Gogolev
quelle
Ich habe einmal einen Auslöser entwickelt, um Zeiten aus ausgewählten Spalten zu bereinigen. Wenn die Daten nicht schlecht sein können, müssen Sie sie nicht bereinigen.
Philip Kelley
2
Der UDF-Ansatz hat einen Nachteil: Sie sind nicht SARG-fähig. Bei Verwendung in JOINs- oder WHERE-Klauseln kann der Optimierer INDEXes nicht zur Verbesserung der Leistung verwenden. Die Verwendung des DATEADD / DATEDIFF-Ansatzes ist jedoch SARGable und kann von INDEXes profitieren. (Anscheinend ist die FLOAT-Methode auch SARGable)
MatBailie
1
@ MatBailie Ich bitte um Unterschied! UDFs sind definitiv nicht SARG-fähig, aber weder Dateadd noch Convert to float! WHERE DateAdd(DateDiff(Column)) = @DateValuewird keinen Index verwenden. Auf der anderen Seite WHERE Column >= dbo.UDF(@DateValue) AND Column < dbo.UDF(@DateValue + 1) ist SARGable. Sei also vorsichtig, wie du es ausdrückst.
ErikE
2

Siehe folgende Frage:
Wie kann ich eine Datums- / Uhrzeitangabe in SQL Server kürzen?

Verwenden Sie auf keinen Fall die Zeichenfolgenmethode . Das ist ungefähr das Schlimmste, was Sie tun können.

Joel Coehoorn
quelle
Danke, ich dachte, das muss vorher gefragt worden sein. Seltsamerweise haben meine Experimente gezeigt, dass die float-Methode unter SQL Server 2008 tatsächlich um 3,5% langsamer ist als die dateadd-Methode (dd, 0, dateiff (dd, 0, getDate ())). Ich habe meine Tests viele Male für jede Methode ausgeführt und der Datenbankserver wurde zu diesem Zeitpunkt für nichts anderes verwendet.
Stephen Perelson
Sagen wir einfach, ich bin skeptisch gegenüber Benchmarks, die von Personen durchgeführt werden, die nicht nachgewiesen haben, dass sie im Rahmen ihrer Arbeit regelmäßig und auf sehr wissenschaftliche Weise Benchmarks durchführen. Sogar Thomas 'Benchmark im Link von gbn hat einige offensichtliche Probleme, wenn man es betrachtet. Das macht es nicht unbedingt falsch, nur nicht endgültig. Die Cast / Floor / Cast-Methode war lange Zeit der am schnellsten akzeptierte Weg, und ich vermute, dass sie einst unbestreitbar zutraf. Das heißt, ich fange an, es zu überdenken; speziell für SQL Server 2008, wo es sowieso völlig unnötig ist.
Joel Coehoorn
1
Die String-Methode ist extrem einfach zu verwenden, zu lesen und sich zu merken. Das sind sehr wichtige Faktoren, die Sie meiner Meinung nach unterschätzen!
Ben
1
@JoelCoehoorn, Konvertierungsstil 121 heißt "ODBC Canonical". Es variiert nicht mit der Sortierung oder dem Gebietsschema. Der String-Trick lässt sich auch leicht auf Jahr, Jahr + Monat, Tag, Stunde oder Minute verallgemeinern.
Ben
1
@Ben Der String-Trick lehrt Entwickler, String-Konvertierungen zu verwenden. Sie funktionieren , aber die Datumsmathematik ist aus vielen Gründen weit überlegen, nicht zuletzt wegen der Geschwindigkeit - aber noch mehr, weil das Lernen, mit Datumsangaben als Zahlen zu arbeiten, dem Entwickler und seinen geistigen Fähigkeiten dies verleiht Seien Sie flüssig mit der Manipulation von Zahlen im Code.
ErikE
2

Bereits beantwortet, aber ich werde das auch rauswerfen ... das soll auch gut vorgeformt sein, aber es funktioniert, indem man die Dezimalstelle (die die Zeit speichert) vom Float wegwirft und nur den ganzen Teil (das ist das Datum) zurückgibt.

 CAST(
FLOOR( CAST( GETDATE() AS FLOAT ) )
AS DATETIME
)

Das zweite Mal, als ich diese Lösung gefunden habe ... habe ich mir diesen Code geholt

Carter Cole
quelle
1
Die Umstellung auf Float ist nicht sicher .
ErikE
2
CAST(round(cast(getdate()as real),0,1) AS datetime)

Diese Methode verwendet keine Zeichenfolgenfunktion. Dateist im Grunde ein realer Datentyp mit Ziffern vor der Dezimalstelle, die Bruchteil eines Tages sind.

Das wird wohl schneller als viel.

Shantanu Singh Chauhan
quelle
1
Das Gießen als Schwimmer ist nicht sicher .
ErikE
2

Für mich ist der folgende Code immer ein Gewinner:

SELECT CONVERT(DATETIME, FLOOR(CONVERT(FLOAT,GETDATE())));
user1920017
quelle
1
Im Wesentlichen dasselbe wie der Vorschlag von @Gary McGill .
Andriy M
1
Das Gießen als Schwimmer ist nicht sicher .
ErikE
2

Wählen Sie CONVERT (char (10), GetDate (), 126).

Diego
quelle
Was ist der Hauptunterschied Ihres Vorschlags zu der in der Antwort von @ broslav genannten Methode oder zu der Methode, die in diesem Thread als am langsamsten ermittelt wurde (gleicher Link wie in der akzeptierten Antwort)?
Andriy M
1

ich denke du meinst cast(floor(cast(getdate()as float))as datetime)

real ist nur 32-Bit und könnte einige Informationen verlieren

Das ist am schnellsten cast(cast(getdate()+x-0.5 as int)as datetime)

... obwohl nur etwa 10% schneller(about 0.49 microseconds CPU vs. 0.58)

Dies wurde empfohlen und dauert in meinem Test gerade genauso lange: DATEADD(dd, DATEDIFF(dd, 0, getdate()), 0)

In SQL 2008 ist die SQL-CLR-Funktion mit 1,35 Mikrosekunden gegenüber 6,5 Mikroschnitten etwa fünfmal schneller als die Verwendung einer SQL-Funktion, was auf einen viel geringeren Overhead für Funktionsaufrufe für eine SQL-CLR-Funktion im Vergleich zu einer einfachen SQL-UDF hinweist.

In SQL 2005 ist die SQL CLR-Funktion laut meinen Tests 16-mal schneller als diese langsame Funktion:

create function dateonly (  @dt datetime )
returns datetime
as
begin
return cast(floor(cast(@dt as float))as int)
end
Aaron West
quelle
1

Wie wäre es select cast(cast my_datetime_field as date) as datetime)? Dies führt zu demselben Datum mit der Uhrzeit 00:00, vermeidet jedoch jegliche Konvertierung in Text und vermeidet auch explizite numerische Rundungen.

Dr. Drew
quelle
Sie sind nicht gleich. Die anderen Antworten schlugen vor, es auf ein Datum ohne Zeitkomponente zu setzen und es so zu belassen. Mein Beitrag setzt es auf eine Datumszeit mit der Zeit um Mitternacht. Es gibt einen großen Unterschied; Wenn Sie versuchen, nach MS Excel zu exportieren, werden Sie feststellen, dass die Datums- und Uhrzeitangaben viel besser als die Datumsangaben sind.
Dr. Drew
Der erste ist genau der gleiche.
Mikael Eriksson
Ok, ja, das sehe ich jetzt. Gerne entferne ich meine Antwort bei Bedarf als Duplikat.
Dr. Drew
1

Ich denke, wenn Sie sich strikt daran halten TSQL, ist dies der schnellste Weg, um die Zeit zu verkürzen:

 select convert(datetime,convert(int,convert(float,[Modified])))

Ich fand diese Kürzungsmethode etwa 5% schneller als die DateAddMethode. Und dies kann leicht so geändert werden, dass es auf den nächsten Tag rundet:

select convert(datetime,ROUND(convert(float,[Modified]),0))
Jamie G.
quelle
Die Umstellung auf Float ist nicht sicher .
ErikE
1

Hier habe ich eine Funktion zum Entfernen einiger Teile einer Datums- / Uhrzeitangabe für SQL Server erstellt. Verwendungszweck:

  • Der erste Parameter ist die Datums- / Uhrzeit, die entfernt werden soll.
  • Der zweite Parameter ist ein Zeichen:
    • s: Runden auf Sekunden; Entfernt Millisekunden
    • m: Runden zu Minuten; Entfernt Sekunden und Millisekunden
    • h: Runden zu Stunden; Entfernt Minuten, Sekunden und Millisekunden.
    • d: Runden zu Tagen; Entfernt Stunden, Minuten, Sekunden und Millisekunden.
  • Gibt die neue datetime zurück

create function dbo.uf_RoundDateTime(@dt as datetime, @part as char) returns datetime as begin if CHARINDEX( @part, 'smhd',0) = 0 return @dt; return cast( Case @part when 's' then convert(varchar(19), @dt, 126) when 'm' then convert(varchar(17), @dt, 126) + '00' when 'h' then convert(varchar(14), @dt, 126) + '00:00' when 'd' then convert(varchar(14), @dt, 112) end as datetime ) end

Max Vargas
quelle
Danke Andriy! Ich wusste nicht, dass meine Empfehlung nicht so effizient war. Zumindest funktioniert es, aber Sie haben Recht.
Max Vargas
1

Nur für den Fall, dass hier jemand nach einer Sybase-Version sucht, da einige der oben genannten Versionen nicht funktioniert haben

CAST(CONVERT(DATE,GETDATE(),103) AS DATETIME)
  • Getestet in I SQL v11 unter Adaptive Server 15.7
Alan
quelle
Dies passt besser als Bearbeitung der akzeptierten Antwort. Mit 20 weiteren Antworten wird dies begraben und nahezu unauffindbar sein. In der akzeptierten Antwort wird auch die Verwendung erwähnt cast: Für SQL Server 2008+ können Sie bisher CAST verwenden. Oder verwenden Sie einfach das Datum, damit Sie keine Zeit zum Entfernen haben.
EWit
Es ist am besten, dies als Antwort auf eine gleichwertige Sybase-Frage zu posten. Wenn es keine solche Frage gibt, können Sie eine erstellen (und diese selbst beantworten).
Andriy M
Außerdem ist es sinnlos , einen dritten Parameter CONVERT angeben , wenn Sie eine konvertieren datetimezu date: keiner von dem hat ein inhärentes Format.
Andriy M
0

Wenn möglich, verwende ich für spezielle Dinge wie diese gerne CLR-Funktionen.

In diesem Fall:

[Microsoft.SqlServer.Server.SqlFunction]
    public static SqlDateTime DateOnly(SqlDateTime input)
    {
        if (!input.IsNull)
        {
            SqlDateTime dt = new SqlDateTime(input.Value.Year, input.Value.Month, input.Value.Day, 0, 0, 0);

            return dt;
        }
        else
            return SqlDateTime.Null;
    }
tjeuten
quelle
0

Ich persönlich verwende hierfür fast immer benutzerdefinierte Funktionen, wenn ich mich mit SQL Server 2005 (oder einer niedrigeren Version) befasse. Es sollte jedoch beachtet werden, dass die Verwendung von UDFs bestimmte Nachteile hat, insbesondere wenn sie auf WHERE-Klauseln angewendet werden (siehe unten und die Kommentare zu dieser Antwort für weitere Details). Bei Verwendung von SQL Server 2008 (oder höher) - siehe unten.

Tatsächlich füge ich für die meisten Datenbanken, die ich erstelle, diese UDFs gleich zu Beginn hinzu, da ich weiß, dass die Wahrscheinlichkeit, dass ich sie früher oder später benötige, bei 99% liegt.

Ich erstelle eine für "nur Datum" und "nur Zeit" (obwohl die "nur Datum" bei weitem die am häufigsten verwendete von beiden ist).

Hier sind einige Links zu verschiedenen datumsbezogenen UDFs:

Wichtige SQL Server-Funktionen für Datum, Uhrzeit und Datum / Uhrzeit Funktion " Nur Datum abrufen"

Dieser letzte Link zeigt nicht weniger als drei verschiedene Möglichkeiten, um das Datum nur als Teil eines Datums- / Uhrzeitfelds abzurufen, und nennt einige Vor- und Nachteile der einzelnen Ansätze.

Wenn Sie eine UDF verwenden, sollten Sie beachten, dass Sie versuchen sollten, die Verwendung der UDF als Teil einer WHERE-Klausel in einer Abfrage zu vermeiden, da dies die Leistung der Abfrage erheblich beeinträchtigt. Der Hauptgrund dafür ist, dass die Verwendung einer UDF in einer WHERE-Klausel diese Klausel als nicht sargable darstellt. Dies bedeutet, dass SQL Server keinen Index mehr mit dieser Klausel verwenden kann, um die Geschwindigkeit der Abfrageausführung zu verbessern. In Bezug auf meine eigene Verwendung von UDFs verwende ich häufig die Spalte "Rohdatum" in der WHERE-Klausel, wende die UDF jedoch auf die Spalte SELECTed an. Auf diese Weise wird die UDF nur auf die gefilterte Ergebnismenge und nicht auf jede Zeile der Tabelle als Teil des Filters angewendet.

Natürlich ist der absolute beste ist Ansatz für diesen SQL Server 2008 (oder höher) zu verwenden und Ihre abscheiden Daten und Zeiten , als der Motor SQL Server - Datenbank dann nativ wird die einzelnen Datums- und Zeitkomponenten bereitstellt, und kann effizient Abfrage dieser unabhängig ohne dass eine UDF oder ein anderer Mechanismus erforderlich ist, um entweder den Datums- oder den Uhrzeitteil aus einem zusammengesetzten Datums- / Uhrzeittyp zu extrahieren.

CraigTP
quelle
Die Verwendung einer UDF kann in einigen Situationen sinnvoll sein (z. B. beim Schrubben von Parametern). Aber in den meisten Fällen ist es eine schreckliche Lösung - läuft ein UDF einmal für jede Zeile ein Weg ist, einfach zu töten die Leistung einer Abfrage, ohne dass es!
ErikE
@ErikE - Ich bin nicht anderer Meinung, Erik, UDFs sind Leistungskiller, weshalb ich sage, wenn Sie SQL Server 2008 oder höher verwenden und einen integrierten Datentyp verwenden, der dies für Sie erledigt, ist dies die beste Lösung (sowohl in Bezug auf das Erreichen der Anforderungen als auch in Bezug auf die Leistung). Wenn Sie mit einer älteren Version von SQL Server nicht weiterkommen, die dies nicht nativ unterstützt, werden Sie etwas aufgeben , um Ihre Anforderungen zu erfüllen.
CraigTP
Wahr. Es wäre schön, wenn die Datenbank-Engine uns etwas geben würde, das SARG-fähig, aber einfacher auszudrücken ist. Wenn Sie in der Zwischenzeit nach einem Wert suchen, der einen ganzen Tag lang verfügbar ist, ist dies immer noch die beste Lösung (für mindestens ältere SQL-Versionen) : WHERE DateColumn >= {TimeTruncatingExpression}(@DateValue) AND DateColumn < {TimeTruncatingExpression}(@DateValue + 1). Ich hatte das Gefühl, dass ich etwas sagen musste, da Sie sagten "Ich verwende fast immer UDFs", was weder die Nachteile noch die Möglichkeit, eine Nur-Datum-Abfrage SARGable zu erstellen, erklärte.
ErikE
@ErikE - Keine Sorge, Erik. Wenn ich UDFs verwendet habe, habe ich entweder mit kleinen Datenmengen gearbeitet, bei denen die Leistung nicht im Vordergrund steht, oder ich habe die Abfrage eher nach dem "rohen" Datumsfeld gefiltert (um die Sargabilität sicherzustellen), aber die Spalte ausgewählt mit der UDF angewendet. Da es sich normalerweise um kleine Datasets handelt, die einmal gefiltert wurden, ist das Ausführen der UDF über diese kleine Anzahl von Datensätzen kein solcher Leistungseinbruch. Das heißt, Sie sprechen einen sehr guten Punkt an und ich habe meine Antwort aktualisiert, um dies widerzuspiegeln.
CraigTP
-4

Ich würde ... benutzen:

CAST
(
CAST(YEAR(DATEFIELD) as varchar(4)) + '/' CAST(MM(DATEFIELD) as varchar(2)) + '/' CAST(DD(DATEFIELD) as varchar(2)) as datetime
) 

So erstellen Sie effektiv ein neues Feld aus dem Datumsfeld, das Sie bereits haben.

Jabu
quelle
2
Warum würdest du das tun? Denken Sie, dass es besser ist , Bits aus einem datetimeWert zu extrahieren , sie in Zeichenfolgen zu konvertieren, diese miteinander zu verketten und das Ergebnis schließlich wieder in zu konvertieren, datetimeals z. B. direkte Berechnungen für das Original datetime(die DATEADD/ DATEDIFF-Methode) durchzuführen ?
Andriy M
Auch was sind MMund DD? In SQL Server gibt es keine derartigen Funktionen.
Andriy M