2009-08-12 15 views
66

Mam zapytanie, które liczy się termin ślubnych użytkownika w bazie danych ...W jaki sposób uzyskujesz "datę rozpoczęcia tygodnia" i "datę zakończenia tygodnia" od numeru tygodnia w SQL Server?

Select 
    Sum(NumberOfBrides) As [Wedding Count], 
    DATEPART(wk, WeddingDate) as [Week Number], 
    DATEPART(year, WeddingDate) as [Year] 
FROM MemberWeddingDates 
Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
Order By Sum(NumberOfBrides) Desc 

Jak mogę pracować, gdy początek i koniec każdego tygodnia reprezentowane w wyniku ustawić?

Select 
     Sum(NumberOfBrides) As [Wedding Count], 
     DATEPART(wk, WeddingDate) as [Week Number], 
     DATEPART(year, WeddingDate) as [Year], 
     ??? as WeekStart, 
     ??? as WeekEnd 

    FROM MemberWeddingDates 
    Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
    Order By Sum(NumberOfBrides) Desc 
+1

Twoje pytanie wystarczyło, aby odpowiedzieć na moje pytanie! :) –

Odpowiedz

115

można znaleźć dzień tygodnia i zrobić data dodania na dni, aby uzyskać daty rozpoczęcia i zakończenia ..

DATEADD(dd, -(DATEPART(dw, WeddingDate)-1), WeddingDate) [WeekStart] 

DATEADD(dd, 7-(DATEPART(dw, WeddingDate)), WeddingDate) [WeekEnd] 

Prawdopodobnie również zajrzeć do zdzierając czas od również data.

+2

Należy pamiętać, że ustawienie opcji 'DATA ODSTĘPUJ 'na wartość inną niż 7 powoduje to. – Tomalak

+3

Nie będzie go "łamał", użyje datefirst, aby ustawić parametr WeekStart = na datę, którą DateFirst określa jako pierwszy dzień tygodnia.Twoja wersja będzie zawsze robić poniedziałek i niedzielę jako początek i koniec tygodnia, a nie to, co serwer jest ustawiony jako początek i koniec tygodnia. –

+0

Hm ... To jest ważny punkt, +1. :) W takim razie usunę kopalnię (mimo że był to strzał w stopę, był bardzo dobrze wycelowany. * G *). – Tomalak

31

Oto DATEFIRST agnostyk rozwiązanie:

SET DATEFIRST 4  /* or use any other weird value to test it */ 
DECLARE @d DATETIME 

SET @d = GETDATE() 

SELECT 
    @d ThatDate, 
    DATEADD(dd, (@@DATEFIRST + 5 + DATEPART(dw, @d)) % 7, @d) Monday, 
    DATEADD(dd, 6 - (@@DATEFIRST + 5 + DATEPART(dw, @d)) % 7, @d) Sunday 
+9

To jest świetne, ale poniedziałek nie działał dla mnie, musiałem dodać "0 -", aby otrzymać poniedziałki. Mój kod poniedziałkowy jest teraz: DATEADD (dd, 0 - (@ @DATEFIRST + 5 + DATEPART (dw, @ d))% 7, @d) – Warren

+0

Wznowiono zarówno odpowiedź, jak i komentarz do Warrens. Serwer Sql w wersji 11.0.5058.0 co najmniej podaje błędną datę w poniedziałek bez modyfikacji Warrenów. ja zamiast piątku. – Morvael

1

Poniżej zapytania dadzą danych pomiędzy początkiem a końcem bieżącego tygodnia począwszy od niedzieli do soboty

SELECT DOB FROM PROFILE_INFO WHERE DAY(DOB) BETWEEN 
DAY(CURRENT_DATE() - (SELECT DAYOFWEEK(CURRENT_DATE())-1)) 
AND 
DAY((CURRENT_DATE()+(7 - (SELECT DAYOFWEEK(CURRENT_DATE()))))) 
AND 
MONTH(DOB)=MONTH(CURRENT_DATE()) 
0

Właśnie spotkać podobny przypadek z ten, ale rozwiązanie tutaj wydaje się nie pomagać mi. Więc próbuję sam to rozgryźć. Wypracowuję tylko datę rozpoczęcia tygodnia, data końca tygodnia powinna być podobnej logiki.

Select 
     Sum(NumberOfBrides) As [Wedding Count], 
     DATEPART(wk, WeddingDate) as [Week Number], 
     DATEPART(year, WeddingDate) as [Year], 
     DATEADD(DAY, 1 - DATEPART(WEEKDAY, dateadd(wk, DATEPART(wk, WeddingDate)-1, DATEADD(yy,DATEPART(year, WeddingDate)-1900,0))), dateadd(wk, DATEPART(wk, WeddingDate)-1, DATEADD(yy,DATEPART(year, WeddingDate)-1900,0))) as [Week Start] 

FROM MemberWeddingDates 
Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
Order By Sum(NumberOfBrides) Desc 
-4

zapytań Access można użyć w poniższej formie jako pole

"FirstDayofWeek:IIf(IsDate([ForwardedForActionDate]),CDate(Format([ForwardedForActionDate],"dd/mm/yyyy"))-(Weekday([ForwardedForActionDate])-1))" 

bezpośredni Obliczanie dozwolonym ..

11

można również użyć tego:

SELECT DATEADD(day, DATEDIFF(day, 0, WeddingDate) /7*7, 0) AS weekstart, 
     DATEADD(day, DATEDIFF(day, 6, WeddingDate-1) /7*7 + 7, 6) AS WeekEnd 
-3

Nie jestem pewien, na ile to jest przydatne, ale znalazłem się tutaj, szukając rozwiązania na Netezza SQL i nie mogłem znaleźć jednego na przepełnieniu stosu .

Dla IBM Netezza chcesz wykorzystać coś (za tydzień rozpocznie mon, week end słońce) jak:

wybrać next_day (WeddingDate 'Sun') -6 jako WeekStart,

next_day (WeddingDate, "SUN") jako Weekend

2

Oto kolejna wersja. Jeśli scenariusz wymaga sobotę będzie 1. dzień tygodnia i piątek będzie ostatni dzień tygodnia, poniższy kod będzie obsługiwać że:

DECLARE @myDate DATE = GETDATE() 
    SELECT @myDate, 
    DATENAME(WEEKDAY,@myDate), 
    DATEADD(DD,-(CHOOSE(DATEPART(dw, @myDate), 2,3,4,5,6,7,1)-1),@myDate) AS WeekStartDate, 
    DATEADD(DD,7-CHOOSE(DATEPART(dw, @myDate), 2,3,4,5,6,7,1),@myDate) AS WeekEndDate 

Screenshot of Query

1

Rozszerzając @Tomalak's odpowiedź. Formuła działa przez kilka dni innych niż niedziela i poniedziałek, ale musisz użyć innych wartości dla miejsca 5. Droga do osiągnięcia wartości potrzebne jest

Value Needed = 7 - (Value From Date First Documentation for Desired Day Of Week) - 1 

tu jest link do dokumentu: https://msdn.microsoft.com/en-us/library/ms181598.aspx

I tutaj jest tabela, która określa go dla Ciebie.

  | DATEFIRST VALUE | Formula Value | 7 - DATEFIRSTVALUE - 1 
Monday | 1    |   5  | 7 - 1- 1 = 5 
Tuesday | 2    |   4  | 7 - 2 - 1 = 4 
Wednesday | 3    |   3  | 7 - 3 - 1 = 3 
Thursday | 4    |   2  | 7 - 4 - 1 = 2 
Friday | 5    |   1  | 7 - 5 - 1 = 1 
Saturday | 6    |   0  | 7 - 6 - 1 = 0 
Sunday | 7    |   -1  | 7 - 7 - 1 = -1 

Ale nie trzeba pamiętać, że stół i tylko formułę, i rzeczywiście można użyć nieco inny jeden za główną potrzebą jest użyć wartości, które uczynią pozostałą prawidłową liczbę dni .

Oto przykład roboczych:

DECLARE @MondayDateFirstValue INT = 1 
DECLARE @FridayDateFirstValue INT = 5 
DECLARE @TestDate DATE = GETDATE() 

SET @MondayDateFirstValue = 7 - @MondayDateFirstValue - 1 
SET @FridayDateFirstValue = 7 - @FridayDateFirstValue - 1 

SET DATEFIRST 6 -- notice this is saturday 

SELECT 
    DATEADD(DAY, 0 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayEndOfWeek 
    ,DATEADD(DAY, 0 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayEndOfWeek 


SET DATEFIRST 2 --notice this is tuesday 

SELECT 
    DATEADD(DAY, 0 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @MondayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as MondayEndOfWeek 
    ,DATEADD(DAY, 0 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayStartOfWeek 
    ,DATEADD(DAY, 6 - (@@DATEFIRST + @FridayDateFirstValue + DATEPART(dw,@TestDate)) % 7, @TestDate) as FridayEndOfWeek 

Ta metoda byłaby agnostyk od ustawienia DATEFIRST co jest to, co potrzebne, jak buduję na wymiar datę z wielu metod tygodniu włączone.

0

Najczęściej wybierana odpowiedź działa dobrze, z wyjątkiem pierwszego tygodnia i ostatniego tygodnia roku. Na przykład jeśli wartością parametru WeddingDate jest "2016-01-01", wynikiem będzie 2015-12-27 i 2016-01-02, ale właściwą odpowiedzią jest 2016-01-01 i 2016-01-02.

Spróbuj tego:

Select 
    Sum(NumberOfBrides) As [Wedding Count], 
    DATEPART(wk, WeddingDate) as [Week Number], 
    DATEPART(year, WeddingDate) as [Year], 
    MAX(CASE WHEN DATEPART(WEEK, WeddingDate) = 1 THEN CAST(DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0) AS date) ELSE DATEADD(DAY, 7 * DATEPART(WEEK, WeddingDate), DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0))) END) as WeekStart, 
    MAX(CASE WHEN DATEPART(WEEK, WeddingDate) = DATEPART(WEEK, DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate) + 1, 0))) THEN DATEADD(DAY, -1, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate) + 1, 0)) ELSE DATEADD(DAY, 7 * DATEPART(WEEK, WeddingDate) + 6, DATEADD(DAY, -(DATEPART(WEEKDAY, DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0)) + 6), DATEADD(YEAR, DATEDIFF(YEAR, 0, WeddingDate), 0))) END) as WeekEnd 
FROM MemberWeddingDates 
Group By DATEPART(year, WeddingDate), DATEPART(wk, WeddingDate) 
Order By Sum(NumberOfBrides) Desc; 

Rezultat wygląda następująco: enter image description here

To działa dla wszystkich tygodnie, 1 lub innych.

1

Pozwól nam rozbić problem do dwóch części:

1) określić dzień tygodnia

W DATEPART(dw, ...) Zwraca liczbę, 1 ... 7, w stosunku do DATEFIRST ustawienia (docs) . Poniższa tabela podsumowuje możliwe wartości:

            @@DATEFIRST 
+------------------------------------+-----+-----+-----+-----+-----+-----+-----+-----+ 
|         | 1 | 2 | 3 | 4 | 5 | 6 | 7 | DOW | 
+------------------------------------+-----+-----+-----+-----+-----+-----+-----+-----+ 
| DATEPART(dw, /*Mon*/ '20010101') | 1 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 
| DATEPART(dw, /*Tue*/ '20010102') | 2 | 1 | 7 | 6 | 5 | 4 | 3 | 2 | 
| DATEPART(dw, /*Wed*/ '20010103') | 3 | 2 | 1 | 7 | 6 | 5 | 4 | 3 | 
| DATEPART(dw, /*Thu*/ '20010104') | 4 | 3 | 2 | 1 | 7 | 6 | 5 | 4 | 
| DATEPART(dw, /*Fri*/ '20010105') | 5 | 4 | 3 | 2 | 1 | 7 | 6 | 5 | 
| DATEPART(dw, /*Sat*/ '20010106') | 6 | 5 | 4 | 3 | 2 | 1 | 7 | 6 | 
| DATEPART(dw, /*Sun*/ '20010107') | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 7 | 
+------------------------------------+-----+-----+-----+-----+-----+-----+-----+-----+ 

Ostatnia kolumna zawiera idealne dzień-of-wartość dla tygodnia od poniedziałku do niedzieli tygodni *. Po prostu patrząc na wykres możemy wymyślić następującym równaniem:

(@@DATEFIRST + DATEPART(dw, SomeDate) - 1 - 1) % 7 + 1 

2) Oblicz poniedziałek i niedzielę na dany dzień

To banalne dzięki wartością dzień-of-tygodnia. Oto przykład:

WITH TestData(SomeDate) AS (
    SELECT CAST('20001225' AS DATETIME) UNION ALL 
    SELECT CAST('20001226' AS DATETIME) UNION ALL 
    SELECT CAST('20001227' AS DATETIME) UNION ALL 
    SELECT CAST('20001228' AS DATETIME) UNION ALL 
    SELECT CAST('20001229' AS DATETIME) UNION ALL 
    SELECT CAST('200' AS DATETIME) UNION ALL 
    SELECT CAST('200' AS DATETIME) UNION ALL 
    SELECT CAST('20010101' AS DATETIME) UNION ALL 
    SELECT CAST('20010102' AS DATETIME) UNION ALL 
    SELECT CAST('20010103' AS DATETIME) UNION ALL 
    SELECT CAST('20010104' AS DATETIME) UNION ALL 
    SELECT CAST('20010105' AS DATETIME) UNION ALL 
    SELECT CAST('20010106' AS DATETIME) UNION ALL 
    SELECT CAST('20010107' AS DATETIME) UNION ALL 
    SELECT CAST('20010108' AS DATETIME) UNION ALL 
    SELECT CAST('20010109' AS DATETIME) UNION ALL 
    SELECT CAST('20010110' AS DATETIME) UNION ALL 
    SELECT CAST('20010111' AS DATETIME) UNION ALL 
    SELECT CAST('20010112' AS DATETIME) UNION ALL 
    SELECT CAST('20010113' AS DATETIME) UNION ALL 
    SELECT CAST('20010114' AS DATETIME) 
), TestDataPlusDOW AS (
    SELECT SomeDate, (@@DATEFIRST + DATEPART(dw, SomeDate) - 1 - 1) % 7 + 1 AS DOW 
    FROM TestData 
) 
SELECT 
    FORMAT(SomeDate,       'ddd yyyy-MM-dd') AS SomeDate, 
    FORMAT(DATEADD(dd, -DOW + 1, SomeDate),  'ddd yyyy-MM-dd') AS [Monday], 
    FORMAT(DATEADD(dd, -DOW + 1 + 6, SomeDate), 'ddd yyyy-MM-dd') AS [Sunday] 
FROM TestDataPlusDOW 

wyjściowa:

+------------------+------------------+------------------+ 
| SomeDate  | Monday   | Sunday  | 
+------------------+------------------+------------------+ 
| Mon 2000-12-25 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Tue 2000-12-26 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Wed 2000-12-27 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Thu 2000-12-28 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Fri 2000-12-29 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Sat 2000-12-30 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Sun 2000-12-31 | Mon 2000-12-25 | Sun 2000-12-31 | 
| Mon 2001-01-01 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Tue 2001-01-02 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Wed 2001-01-03 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Thu 2001-01-04 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Fri 2001-01-05 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Sat 2001-01-06 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Sun 2001-01-07 | Mon 2001-01-01 | Sun 2001-01-07 | 
| Mon 2001-01-08 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Tue 2001-01-09 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Wed 2001-01-10 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Thu 2001-01-11 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Fri 2001-01-12 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Sat 2001-01-13 | Mon 2001-01-08 | Sun 2001-01-14 | 
| Sun 2001-01-14 | Mon 2001-01-08 | Sun 2001-01-14 | 
+------------------+------------------+------------------+ 

* Do niedzieli do soboty tygodnie trzeba dostosować równanie tylko trochę, jak dodać1w gdzieś.