Um zu beantworten, warum Sie einen Montag und keinen Sonntag bekommen:
Sie fügen dem Datum 0 eine Anzahl von Wochen hinzu. Was ist das Datum 0? 1900-01-01. Was war der Tag am 1900-01-01? Montag. In Ihrem Code sagen Sie also, wie viele Wochen sind seit Montag, dem 1. Januar 1900 vergangen? Nennen wir das [n]. Ok, fügen Sie jetzt [n] Wochen zum Montag, dem 1. Januar 1900, hinzu. Sie sollten sich nicht wundern, dass dies ein Montag wird. DATEADD
hat keine Ahnung, dass Sie Wochen hinzufügen möchten, aber nur bis Sie zu einem Sonntag kommen, es werden nur 7 Tage und dann 7 weitere Tage hinzugefügt, ... genau wie DATEDIFF
nur Grenzen erkannt werden, die überschritten wurden. Zum Beispiel geben beide 1 zurück, obwohl sich einige Leute darüber beschweren, dass eine vernünftige Logik eingebaut sein sollte, um auf- oder abzurunden:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Um zu beantworten, wie man einen Sonntag bekommt:
Wenn Sie einen Sonntag wünschen, wählen Sie ein Basisdatum, das kein Montag, sondern ein Sonntag ist. Beispielsweise:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
Dies wird nicht unterbrochen, wenn Sie Ihre DATEFIRST
Einstellung ändern (oder Ihr Code für einen Benutzer mit einer anderen Einstellung ausgeführt wird) - vorausgesetzt, Sie möchten unabhängig von der aktuellen Einstellung weiterhin einen Sonntag. Wenn Sie möchten, dass diese beiden Antworten funktionieren, sollten Sie eine Funktion verwenden, die von der DATEFIRST
Einstellung abhängt , z
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Wenn Sie also Ihre DATEFIRST
Einstellung auf Montag, Dienstag ändern, ändert sich das Verhalten. Je nachdem, welches Verhalten Sie möchten, können Sie eine der folgenden Funktionen verwenden:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
...oder...
CREATE FUNCTION dbo.StartOfWeek2 -- always the DATEFIRST weekday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO
Jetzt haben Sie viele Alternativen, aber welche ist die beste? Ich wäre überrascht, wenn es größere Unterschiede geben würde, aber ich habe alle bisher gegebenen Antworten gesammelt und zwei Testreihen durchlaufen - eine billige und eine teure. Ich habe Client-Statistiken gemessen, weil ich nicht sehe, dass E / A oder Speicher hier eine Rolle bei der Leistung spielen (obwohl diese je nach Verwendung der Funktion ins Spiel kommen können). In meinen Tests sind die Ergebnisse:
Zuweisungsabfrage "Günstig":
Function - client processing time / wait time on server replies / total exec time
Gandarez - 330/2029/2359 - 0:23.6
me datefirst - 329/2123/2452 - 0:24.5
me Sunday - 357/2158/2515 - 0:25.2
trailmax - 364/2160/2524 - 0:25.2
Curt - 424/2202/2626 - 0:26.3
"Teure" Zuweisungsabfrage:
Function - client processing time / wait time on server replies / total exec time
Curt - 1003/134158/135054 - 2:15
Gandarez - 957/142919/143876 - 2:24
me Sunday - 932/166817/165885 - 2:47
me datefirst - 939/171698/172637 - 2:53
trailmax - 958/173174/174132 - 2:54
Auf Wunsch kann ich die Details meiner Tests weitergeben - hier anhalten, da dies bereits ziemlich langwierig wird. Ich war ein bisschen überrascht zu sehen, dass Curt's angesichts der Anzahl der Berechnungen und des Inline-Codes am schnellsten als der schnellste herauskam. Vielleicht führe ich gründlichere Tests durch und blogge darüber ... wenn ihr keine Einwände dagegen habt, dass ich eure Funktionen woanders veröffentliche.
(@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7
bleibt konstant, unabhängig von der@@datefirst
Einstellung, denke ich. Mit Montag = 2.