Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

Obtenir le premier jour de la semaine dans SQL Server

Pour savoir pourquoi vous obtenez un lundi et non un dimanche :

Vous ajoutez un nombre de semaines à la date 0. Qu'est-ce que la date 0 ? 1900-01-01. Quel jour était le 1900-01-01 ? Lundi. Donc dans votre code vous dites combien de semaines se sont écoulées depuis le lundi 1er janvier 1900 ? Appelons cela [n]. Ok, maintenant ajoutez [n] semaines au lundi 1er janvier 1900. Vous ne devriez pas être surpris que cela finisse par être un lundi. DATEADD n'a aucune idée que vous voulez ajouter des semaines, mais seulement jusqu'à ce que vous arriviez à un dimanche, il s'agit simplement d'ajouter 7 jours, puis d'ajouter 7 jours supplémentaires, ... tout comme DATEDIFF ne reconnaît que les limites qui ont été franchies. Par exemple, ces deux éléments renvoient 1, même si certaines personnes se plaignent qu'il devrait y avoir une logique logique intégrée pour arrondir vers le haut ou vers le bas :

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

Pour savoir comment obtenir un dimanche :

Si vous voulez un dimanche, choisissez une date de base qui n'est pas un lundi mais plutôt un dimanche. Par exemple :

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

Cela ne se cassera pas si vous modifiez votre DATEFIRST paramètre (ou votre code est en cours d'exécution pour un utilisateur avec un paramètre différent) - à condition que vous souhaitiez toujours un dimanche quel que soit le paramètre actuel. Si vous voulez que ces deux réponses correspondent, vous devez utiliser une fonction qui fait dépendent de la DATEFIRST paramètre, par exemple

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

Donc, si vous modifiez votre DATEFIRST mise à lundi, mardi, qu'avez-vous, le comportement va changer. Selon le comportement souhaité, vous pouvez utiliser l'une de ces fonctions :

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

...ou...

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

Maintenant, vous avez beaucoup d'alternatives, mais laquelle fonctionne le mieux ? Je serais surpris s'il y avait des différences majeures, mais j'ai rassemblé toutes les réponses fournies jusqu'à présent et les ai soumises à deux séries de tests - un bon marché et un cher. J'ai mesuré les statistiques du client car je ne vois pas les E/S ou la mémoire jouer un rôle dans les performances ici (bien que celles-ci puissent entrer en jeu en fonction de la manière dont la fonction est utilisée). Dans mes tests, les résultats sont :

Requête d'affectation "bon marché" :

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

Requête d'affectation "coûteuse" :

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

Je peux transmettre les détails de mes tests si vous le souhaitez - m'arrêter ici car cela devient déjà assez long. J'ai été un peu surpris de voir que Curt est le plus rapide du haut de gamme, compte tenu du nombre de calculs et du code en ligne. Peut-être que je ferai des tests plus approfondis et que je bloguerai à ce sujet... si vous n'avez aucune objection à ce que je publie vos fonctions ailleurs.