Odpověď, proč máte pondělí a ne neděli:
K datu 0 přidáváte počet týdnů. Co je datum 0? 1900-01-01. Jaký byl den 01.01.1900? Pondělí. Takže ve svém kódu říkáte, kolik týdnů uplynulo od pondělí 1. ledna 1900? Říkejme tomu [n]. Dobře, nyní přidejte [n] týdnů k pondělí 1. ledna 1900. Neměli byste být překvapeni, že z toho nakonec bude pondělí. DATEADD
netuší, že chcete přidat týdny, ale pouze do té doby, než se dostanete do neděle, je to jen přidání 7 dnů, pak přidání dalších 7 dnů, ... stejně jako DATEDIFF
rozpozná pouze hranice, které byly překročeny. Například oba vrátí 1, i když si někteří lidé stěžují, že by měla být zabudována rozumná logika, která by zaokrouhlovala nahoru nebo dolů:
SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');
Odpověď na to, jak získat neděli:
Pokud chcete neděli, vyberte základní datum, které není pondělí, ale neděle. Například:
DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);
Toto nebude přerušeno, pokud změníte DATEFIRST
nastavení (nebo váš kód běží pro uživatele s jiným nastavením) - za předpokladu, že stále chcete neděli bez ohledu na aktuální nastavení. Pokud chcete, aby tyto dvě odpovědi měly jive, měli byste použít funkci, která dělá závisí na DATEFIRST
nastavení, např.
SELECT DATEADD(DAY, 1-DATEPART(WEEKDAY, CURRENT_TIMESTAMP), CURRENT_TIMESTAMP);
Pokud tedy změníte DATEFIRST
nastavení na pondělí, úterý, co máte, chování se změní. V závislosti na tom, jaké chování chcete, můžete použít jednu z těchto funkcí:
CREATE FUNCTION dbo.StartOfWeek1 -- always a Sunday
(
@d DATE
)
RETURNS DATE
AS
BEGIN
RETURN (SELECT DATEADD(WEEK, DATEDIFF(WEEK, '19050101', @d), '19050101'));
END
GO
...nebo...
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
Nyní máte spoustu alternativ, ale která funguje nejlépe? Překvapilo by mě, kdyby tam byly nějaké zásadní rozdíly, ale shromáždil jsem všechny dosud poskytnuté odpovědi a prošel je dvěma sadami testů – jedním levným a druhým drahým. Měřil jsem statistiky klientů, protože nevidím, že zde I/O nebo paměť hrají roli ve výkonu (i když ty mohou hrát roli v závislosti na tom, jak se funkce používá). V mých testech jsou výsledky:
"Levný" dotaz na přiřazení:
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
"Drahý" dotaz na přiřazení:
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
Můžu předat podrobnosti o mých testech, pokud si to přeju - tady se zastavím, protože to už začíná být docela zdlouhavé. Byl jsem trochu překvapen, když jsem viděl, že Curt's vyšel jako nejrychlejší na nejvyšší úrovni, vzhledem k počtu výpočtů a vloženého kódu. Možná provedu důkladnější testy a napíšu o tom blog... pokud nemáte žádné námitky proti tomu, abych vaše funkce zveřejnil jinde.