Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Uzyskaj pierwszy dzień tygodnia w SQL Server

Aby odpowiedzieć, dlaczego masz poniedziałek, a nie niedzielę:

Dodajesz liczbę tygodni do daty 0. Co to jest data 0? 1900-01-01. Jaki był dzień 1900-01-01? Poniedziałek. Więc w swoim kodzie mówisz, ile tygodni minęło od poniedziałku 1 stycznia 1900? Nazwijmy to [n]. Ok, teraz dodaj [n] tygodni do poniedziałku, 1 stycznia 1900. Nie powinieneś się dziwić, że jest to poniedziałek. DATEADD nie ma pojęcia, że ​​chcesz dodać tygodnie, ale tylko do niedzieli, to tylko dodawanie 7 dni, a następnie dodawanie kolejnych 7 dni, ... tak jak DATEDIFF rozpoznaje tylko przekroczone granice. Na przykład oba zwracają 1, mimo że niektórzy ludzie narzekają, że powinna być wbudowana pewna rozsądna logika, aby zaokrąglać 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 zdobyć niedzielę:

Jeśli chcesz niedzielę, wybierz datę bazową, która nie jest poniedziałkiem, ale niedzielą. 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 swój DATEFIRST ustawienie (lub Twój kod działa dla użytkownika z innym ustawieniem) - pod warunkiem, że nadal chcesz mieć niedzielę niezależnie od bieżącego ustawienia. Jeśli chcesz, aby te dwie odpowiedzi były jive, powinieneś użyć funkcji, która robi zależy od DATEFIRST ustawienie, np.

SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);

Więc jeśli zmienisz swój DATEFIRST ustawienie na poniedziałek, wtorek, co masz, zachowanie się zmieni. W zależności od pożądanego zachowania możesz użyć jednej z tych funkcji:

CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
    @d DATE
)
RETURNS DATE
AS
BEGIN
    RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO

...lub...

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

Teraz masz wiele alternatyw, ale która z nich działa najlepiej? Byłbym zdziwiony, gdyby były jakieś większe różnice, ale zebrałem wszystkie dotychczas udzielone odpowiedzi i przepuściłem je przez dwa zestawy testów - jeden tani, a drugi drogi. Zmierzyłem statystyki klienta, ponieważ nie widzę tutaj udziału we/wy ani pamięci w wydajności (chociaż mogą one mieć znaczenie w zależności od tego, jak używana jest funkcja). W moich testach wyniki są następujące:

„Tanie” zapytanie o przydział:

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

„Drogie” zapytanie o przypisanie:

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ść długie. Byłem trochę zaskoczony, widząc, że Curt wyszedł jako najszybszy z najwyższej półki, biorąc pod uwagę liczbę obliczeń i wbudowany kod. Może przeprowadzę dokładniejsze testy i napiszę o tym blog... jeśli nie macie żadnych zastrzeżeń, żebym opublikowała wasze funkcje gdzie indziej.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Określ rozmiar wiersza dla tabeli

  2. Nieużywany indeks programu SQL Server

  3. Zdarzenia oczekiwania serwera SQL -2

  4. Jak zoptymalizować użycie klauzuli OR, gdy jest używana z parametrami (SQL Server 2008)

  5. Nieudane wywołanie ODBC z procedurą składowaną — zapytanie przekazujące