sql >> Database teknologi >  >> RDS >> Sqlserver

Få første dag i ugen i SQL Server

For at svare på, hvorfor du får en mandag og ikke en søndag:

Du tilføjer et antal uger til datoen 0. Hvad er dato 0? 1900-01-01. Hvad var dagen den 1900-01-01? Mandag. Så i din kode siger du, hvor mange uger er der gået siden mandag den 1. januar 1900? Lad os kalde det [n]. Ok, læg nu [n] uger til mandag den 1. januar 1900. Du bør ikke blive overrasket over, at dette ender med at blive en mandag. DATEADD aner ikke at du vil tilføje uger, men kun indtil du kommer til en søndag, det er bare at tilføje 7 dage, så tilføje 7 dage mere, ... ligesom DATEDIFF genkender kun grænser, der er blevet overskredet. For eksempel returnerer disse begge 1, selvom nogle mennesker klager over, at der burde være en fornuftig logik indbygget for at runde op eller ned:

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

Sådan svarer du på, hvordan du får en søndag:

Hvis du vil have en søndag, så vælg en basisdato, der ikke er en mandag, men snarere en søndag. For eksempel:

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

Dette går ikke i stykker, hvis du ændrer din DATEFIRST indstilling (eller din kode kører for en bruger med en anden indstilling) - forudsat at du stadig ønsker en søndag uanset den aktuelle indstilling. Hvis du vil have disse to svar til at jive, så skal du bruge en funktion, der gør afhænger af DATEFIRST indstilling, f.eks.

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

Så hvis du ændrer din DATEFIRST indstilling til mandag, tirsdag, hvad har du, vil adfærden ændre sig. Afhængigt af hvilken adfærd du ønsker, kan du bruge en af ​​disse 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 masser af alternativer, men hvilken klarer sig bedst? Jeg ville blive overrasket, hvis der ville være nogen større forskelle, men jeg samlede alle de svar, der er givet indtil nu, og kørte dem gennem to sæt test - en billig og en dyr. Jeg målte klientstatistikker, fordi jeg ikke kan se I/O eller hukommelse spille en rolle i ydelsen her (selvom de kan komme i spil afhængigt af, hvordan funktionen bruges). I mine test er resultaterne:

"Billig" opgaveforespørgsel:

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" opgaveforespørgsel:

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

Jeg kan videresende detaljerne i mine tests, hvis det ønskes - stopper her, da det allerede er ved at blive ret langhåret. Jeg var en smule overrasket over at se Curt's komme ud som den hurtigste i den høje ende, givet antallet af beregninger og inline kode. Måske vil jeg køre nogle mere grundige tests og blogge om det... hvis I ikke har nogen indvendinger mod, at jeg udgiver jeres funktioner andre steder.



  1. Sådan ændres datoformatet i din Oracle-session

  2. Opgradering af en varchar-kolonne til enum type i postgresql

  3. Sådan bruges SQL Server HierarchyID gennem nemme eksempler

  4. Brug af lagrede procedure-outputparametre i C#