Om te beantwoorden waarom je een maandag krijgt en geen zondag:
Je voegt een aantal weken toe aan de datum 0. Wat is de datum 0? 1900-01-01. Wat was de dag op 01-01-00? Maandag. Dus in uw code zegt u, hoeveel weken zijn er verstreken sinds maandag 1 januari 1900? Laten we dat [n] noemen. Oké, tel nu [n] weken op bij maandag 1 januari 1900. Het zal je niet verbazen dat dit uiteindelijk een maandag wordt. DATEADD
heeft geen idee dat je weken wilt toevoegen, maar alleen totdat je op een zondag komt, het is gewoon 7 dagen toevoegen, dan nog 7 dagen toevoegen, ... net als DATEDIFF
herkent alleen grenzen die zijn overschreden. Deze retourneren bijvoorbeeld beide 1, hoewel sommige mensen klagen dat er een redelijke logica moet zijn ingebouwd om naar boven of naar beneden af te ronden:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Beantwoorden hoe je een zondag kunt krijgen:
Als je een zondag wilt, kies dan een basisdatum die geen maandag is maar eerder een zondag. Bijvoorbeeld:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
Dit gaat niet kapot als je je DATEFIRST
. wijzigt instelling (of uw code is actief voor een gebruiker met een andere instelling) - op voorwaarde dat u nog steeds een zondag wilt, ongeacht de huidige instelling. Als je wilt dat die twee antwoorden jive zijn, moet je een functie gebruiken die doet afhankelijk van de DATEFIRST
instelling, bijv.
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Dus als u uw DATEFIRST
. wijzigt instelling op maandag, dinsdag, wat heb je, het gedrag zal veranderen. Afhankelijk van welk gedrag u wilt, kunt u een van deze functies gebruiken:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
...of...
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
Nu heb je genoeg alternatieven, maar welke presteert het beste? Het zou me verbazen als er grote verschillen zouden zijn, maar ik heb alle antwoorden die tot nu toe zijn gegeven verzameld en ze door twee sets tests laten lopen - een goedkope en een dure. Ik heb klantstatistieken gemeten omdat ik I/O of geheugen hier geen rol zie spelen in de uitvoering (hoewel die een rol kunnen spelen, afhankelijk van hoe de functie wordt gebruikt). In mijn tests zijn de resultaten:
"Goedkope" opdrachtopdracht:
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
"Dure" opdrachtopdracht:
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
Ik kan de details van mijn tests desgewenst doorgeven - hier stoppen omdat dit al behoorlijk langdradig wordt. Ik was een beetje verrast om te zien dat Curt's aan de hoge kant als de snelste uitkwam, gezien het aantal berekeningen en inline code. Misschien zal ik wat grondigere tests uitvoeren en erover bloggen... als jullie er geen bezwaar tegen hebben dat ik jullie functies ergens anders publiceer.