sql >> Databáze >  >> RDS >> Sqlserver

Získejte první den v týdnu na serveru SQL

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.



  1. Jak zajistíte, aby přední fulltextové vyhledávání se zástupnými znaky fungovalo na serveru SQL Server?

  2. Uložená procedura pro získání stavu indexů ve všech databázích

  3. Jak vybrat všechny záznamy z jedné tabulky, které neexistují v jiné tabulce?

  4. Jak drahé jsou implicitní konverze na straně sloupců?