Aby odpowiedzieć, dlaczego otrzymujesz poniedziałek, a nie niedzielę:
Dodajesz liczbę tygodni do daty 0. Co to jest data 0? 1900-01-01. Jaki był dzień 01.01.1900? Poniedziałek. Więc w swoim kodzie mówisz, ile tygodni minęło od poniedziałku 1 stycznia 1900 roku? Nazwijmy to [n]. Ok, teraz dodaj [n] tygodni do poniedziałku 1 stycznia 1900. Nie powinieneś być zaskoczony, że kończy się to w poniedziałek. DATEADD
nie ma pojęcia, że chcesz dodawać tygodnie, ale tylko do niedzieli, po prostu dodaje 7 dni, a następnie dodaje 7 kolejnych dni ... tak jak DATEDIFF
rozpoznaje tylko granice, które zostały przekroczone. Na przykład oba zwracają 1, mimo że niektórzy ludzie narzekają, że powinna być wbudowana rozsądna logika do zaokrąglania w górę lub w dół:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Aby odpowiedzieć, jak dostać niedzielę:
Jeśli chcesz niedzielę, wybierz datę bazową, która nie jest poniedziałek, ale raczej niedziela. Na przykład:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
To się nie zepsuje, jeśli zmienisz swoje DATEFIRST
ustawienie (lub Twój kod jest uruchomiony dla użytkownika z innym ustawieniem) - pod warunkiem, że nadal chcesz niedzielę, niezależnie od bieżącego ustawienia. Jeśli chcesz, aby te dwie odpowiedzi były jive, powinieneś użyć funkcji, która zależy od DATEFIRST
ustawienia, np
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Więc jeśli zmienisz DATEFIRST
ustawienie na poniedziałek, wtorek, co masz, zachowanie się zmieni. W zależności od tego, jakiego zachowania chcesz, możesz użyć jednej z następujących funkcji:
CREATE FUNCTION dbo.StartOfWeek1
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
...lub...
CREATE FUNCTION dbo.StartOfWeek2
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, @d), @d));
END
GO
Masz teraz wiele alternatyw, ale która z nich działa najlepiej? Zdziwiłbym się, gdyby były jakieś większe różnice, ale zebrałem wszystkie dotychczas udzielone odpowiedzi i przeprowadziłem je przez dwa zestawy testów - jeden tani i jeden drogi. Zmierzyłem statystyki klienta, ponieważ nie widzę tutaj I / O lub pamięci odgrywających rolę w wydajności (chociaż mogą one mieć znaczenie w zależności od sposobu wykorzystania funkcji). W moich testach wyniki to:
Zapytanie o przypisanie „Tanie”:
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
Zapytanie o przypisanie „Drogie”:
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
W razie potrzeby mogę przekazać szczegóły moich testów - zatrzymując się tutaj, ponieważ jest to już dość rozwlekłe. Byłem trochę zaskoczony, widząc, że Curt wyszedł jako najszybszy na najwyższym poziomie, biorąc pod uwagę liczbę obliczeń i kod wbudowany. Może przeprowadzę dokładniejsze testy i napiszę o tym na blogu ... jeśli nie macie żadnych zastrzeżeń co do tego, żebym opublikował wasze funkcje gdzie indziej.
(@@DATEFIRST + DATEPART(DW, @SomeDate)) % 7
@@datefirst
myślę, że pozostaje niezmienna niezależnie od ustawienia. Poniedziałek = 2.