2010-02-13 6 views
1

Je me rends compte que différentes solutions auront différentes variations de ce que les «jours ouvrables» signifient mais dans mon cas, je veux dire du lundi au vendredi inclusivement.Calculer combien de jours de travail entre deux dates - T-SQL?

Fondamentalement, j'ai créé une fonction pour faire le calcul pour moi et ma solution actuelle fonctionne. Mon inquiétude (et la raison pour laquelle je pose cette question) est que je crains que ce soit une mauvaise façon d'y parvenir parce que la fonction est appelée avec une très grande fréquence. Au cours des 3 derniers mois, il a été appelé 12 millions de fois sur un système de production, avec un temps de travail moyen de 44ms. Cela m'a amené à me demander si c'est la bonne façon de parvenir à une solution.

Tout d'abord ici est la fonction que j'ai créé:

CREATE FUNCTION [dbo].[fn_WorkDays] 
    (
    @StartDate DATETIME, 
    @EndDate DATETIME = NULL [email protected] replaced by @StartDate when DEFAULTed 
    ) 
    RETURNS INT 
AS 

BEGIN 
    --===== Declare local variables 
    --Temporarily holds @EndDate during date reversal 
    DECLARE @Swap DATETIME 

    --===== If the Start Date is null, return a NULL and exit 
     IF @StartDate IS NULL 
      RETURN NULL 

    --===== If the End Date is null, populate with Start Date value 
     -- so will have two dates (required by DATEDIFF below) 
     IF @EndDate IS NULL 
      SELECT @EndDate = @StartDate 

    --===== Strip the time element from both dates (just to be safe) by converting 
     -- to whole days and back to a date. Usually faster than CONVERT. 
     -- 0 is a date (01/01/1900 00:00:00.000) 
    SELECT @StartDate = DATEADD(dd,DATEDIFF(dd,0,@StartDate),0), 
      @EndDate = DATEADD(dd,DATEDIFF(dd,0,@EndDate) ,0) 

    --===== If the inputs are in the wrong order, reverse them 
     IF @StartDate > @EndDate 
      SELECT @Swap  = @EndDate, 
        @EndDate = @StartDate, 
        @StartDate = @Swap 

    --===== Calculate and return the number of workdays using the 
     -- input parameters. This is the meat of the function. 
     -- This is really just one formula with a couple of parts 
     -- that are listed on separate lines for documentation 
     -- purposes. 
    RETURN (
      SELECT 
      --Start with total number of days including weekends 
      (DATEDIFF(dd,@StartDate,@EndDate)+1) 

      --Subtact 2 days for each full weekend 
      -(DATEDIFF(wk,@StartDate,@EndDate)*2) 

      --If StartDate is a Sunday, Subtract 1 
      -(CASE WHEN DATENAME(dw,@StartDate) = 'Sunday' 
        THEN 1 
        ELSE 0 
       END) 

      --If EndDate is a Saturday, Subtract 1 
      -(CASE WHEN DATENAME(dw,@EndDate) = 'Saturday' 
        THEN 1 
        ELSE 0 
       END) 
      ) 
END 

Comme un exemple simple de son utilisation, je courrais ce type de requête:

SELECT MYTABLE.EntryDate 
    ,dbo.fn_WorkDays(MYTABLE.EntryDate, getutcdate()) as WorkingDays 
    FROM MYTABLE          

MyTable pourrait contenir 5000 lignes, toutes avec des dates différentes dans la colonne EntryDate (5000 appels à la fonction)

Ma question est que je manque quelque chose ici dans la façon dont je fais cela, serait-il bénéfique de créer un loo Table Kup pour cela (mais qui est beaucoup de combinaisons de dates)

Toutes les pensées, les améliorations ou recommandations seront appréciées ...

+0

Jetez un oeil à cette réponse et de comparer les notes: http://stackoverflow.com/questions/1828948/mysql-function-to-find-the-number-of-working-days-between-two-dates/1828991 # 1828991 –

+0

Est-il possible pour vous d'ajouter un champ supplémentaire (un champ calculé) et le mettre à jour avec la différence en jours seulement quand les valeurs changent? Je veux dire, quel est le point de faire la différence à chaque fois? – shahkalpesh

+0

Comparer toujours une date stockée par rapport à aujourd'hui ... donc mettre à jour au moins une fois par jour (ce qui est une option) –

Répondre

2

Je ne pense pas que vous puissiez faire beaucoup de choses avec l'UDF tbh - le fait de le calculer au moment de l'exécution comme cela en SQL va toujours provoquer un hit dans une certaine mesure. Donc, idéalement (et cela peut ne pas être possible car je ne connais pas l'image complète), je pense que ce que je ferais est de stocker le nombre de jours de travail dans votre table et de le calculer UNE FOIS lorsque l'enregistrement est créé. Si ce n'est pas possible (c.-à-d. Lorsque l'enregistrement est créé, vous n'avez pas de «date de fin»), alors je considérerais un travail planifié chaque soir pour recalculer tous enregistrements particuliers afin qu'ils soient mis à jour chaque jour - puis, lorsqu'une "date de fin" est saisie, cet enregistrement n'est pas inclus dans cette mise à jour par lots. Les avantages de cela, vous décharger les calculs à une période plus calme, et ne font que les calculs une fois par jour. La requête devient beaucoup plus simple et plus performante car elle peut simplement lire le numéro WorkingDays de la table.

Si ce n'est pas une option, alors je suggère de faire les calculs dans le frontend, retirer le hit de la DB.

+0

Parce que le calcul est toujours basé sur aujourd'hui, j'aurais besoin d'assigner une valeur quotidienne plutôt qu'au moment de la création de l'enregistrement (peut-être aussi, pour initialiser la valeur quand un enregistrement est créé?), Bon appel. –

+0

@Simon - Je pensais que ce serait le cas. Mais je pense qu'il vaut la peine d'envisager l'approche de mise à jour nocturne. La mise à jour une fois par jour pourrait grandement améliorer les performances de reporting - en particulier si le calcul est effectué plusieurs fois dans la journée – AdaTheDev

0

Il y a deux problèmes:

  1. Calculer le nombre de jours entre deux dates,
  2. Indiquer si oui ou non une date donnée est un "jour ouvrable".

Le second comprend plus faciles comme « semaine » et « week-end », des vacances (laïques, religieuses et juridiques), etc.

Vous aurez besoin de résoudre à la fois. Le premier est plus facile, parce que les bases de données relationnelles auront des fonctions pour vous aider. C'est la seconde qui est la plus difficile et la plus variable, car elle change en fonction des paramètres régionaux et des activités.

+0

Mes exigences sont plus simples que cela, je me fous des vacances qui excluent tout simplement les week-ends ... ma solution fait cela, je veux juste être sûr d'avoir manqué un tour ici et exécute la solution de la manière la plus efficace. –

+0

Noël, Nouvel An, etc - pas besoin de s'inquiéter de ceux-ci? Ensuite, c'est un problème plus facile. – duffymo

+0

Pas pour le moment non, je suis juste préoccupé par ma mise en œuvre de la solution à mon problème. –

Questions connexes