sql >> Databasteknik >  >> RDS >> Sqlserver

Få första veckodagen i SQL Server

För att svara på varför du får en måndag och inte en söndag:

Du lägger till ett antal veckor till datum 0. Vad är datum 0? 1900-01-01. Vilken var dagen den 1900-01-01? måndag. Så i din kod säger du, hur många veckor har gått sedan måndagen den 1 januari 1900? Låt oss kalla det [n]. Ok, lägg nu till [n] veckor till måndagen den 1 januari 1900. Du borde inte bli förvånad över att detta slutar med att bli en måndag. DATEADD har ingen aning om att du vill lägga till veckor men bara tills du kommer till en söndag, det är bara att lägga till 7 dagar, sedan lägga till 7 dagar till, ... precis som DATEDIFF känner bara igen gränser som har passerats. Till exempel, dessa returnerar båda 1, även om vissa människor klagar på att det borde finnas någon vettig logik inbyggd för att avrunda uppåt eller nedåt:

SELECT DATEDIFF(YEAR, '2010-01-01', '2011-12-31');
SELECT DATEDIFF(YEAR, '2010-12-31', '2011-01-01');

Så här svarar du på hur du får en söndag:

Om du vill ha en söndag, välj ett basdatum som inte är en måndag utan snarare en söndag. Till exempel:

DECLARE @dt DATE = '1905-01-01';
SELECT [start_of_week] = DATEADD(WEEK, DATEDIFF(WEEK, @dt, CURRENT_TIMESTAMP), @dt);

Detta kommer inte att gå sönder om du ändrar din DATEFIRST inställning (eller så körs din kod för en användare med en annan inställning) - förutsatt att du fortfarande vill ha en söndag oavsett aktuell inställning. Om du vill att dessa två svar ska jive, bör du använda en funktion som gör beror på DATEFIRST inställning, t.ex.

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

Så om du ändrar din DATEFIRST inställning till måndag, tisdag, vad har du, beteendet kommer att förändras. Beroende på vilket beteende du vill kan du använda någon av dessa funktioner:

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

...eller...

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 har du massor av alternativ, men vilken fungerar bäst? Jag skulle bli förvånad om det skulle finnas några större skillnader men jag samlade alla svar som givits hittills och körde dem genom två uppsättningar tester - ett billigt och ett dyrt. Jag mätte klientstatistik eftersom jag inte ser att I/O eller minne spelar en roll i prestandan här (även om de kan spela in beroende på hur funktionen används). I mina tester är resultaten:

"Billig" uppdragsfråga:

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

"Dyr" tilldelningsfråga:

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

Jag kan vidarebefordra detaljerna i mina tester om så önskas - sluta här eftersom det här redan börjar bli ganska långrandigt. Jag blev lite förvånad över att se Curt's komma ut som den snabbaste i high end, med tanke på antalet beräkningar och inline-kod. Jag kanske kör lite mer grundliga tester och bloggar om det... om ni inte har några invändningar mot att jag publicerar era funktioner någon annanstans.



  1. Konvertera 'datetime' till 'date' i SQL Server (T-SQL-exempel)

  2. Använd DB_ID() för att returnera ID:t för en databas i SQL Server

  3. SQL-fråga dynamiskt tabellnamn i FOR

  4. Fixa "Konvertering misslyckades vid konvertering av varchar-värdet" När du försöker sammanfoga i SQL Server