除自定义工作日外的所有记录的总和日期差

时间:2018-06-30 23:37:59

标签: sql sql-server

我在通过Google搜索时发现了这个有用的查询:

SELECT
    SUM((DATEDIFF(dd, vacFrom, vacTo) + 1)
       -(DATEDIFF(wk, vacFrom, vacTo) * 2)
       -(CASE WHEN DATENAME(dw, vacFrom)='Friday' THEN 1 ELSE 0 END)
       -(CASE WHEN DATENAME(dw, vacTo)='Friday' THEN 1 ELSE 0 END)
       -(CASE WHEN DATENAME(dw, vacFrom)='Saturday' THEN 1 ELSE 0 END)
      -(CASE WHEN DATENAME(dw, vacTo)='Saturday' THEN 1 ELSE 0 END))
FROM 
    MS_users_vacations 
WHERE 
    YEAR(vacFrom) = 2018

例如,它的用途:获取雇员一年的总休假天数,如果有休假期间,则不包括周末,因此, vacFrom 是休假的开始日期并且 vacTo 是结束日期。但是如果自定义周末,如何获得相同的结果?我的意思是,如果我想对所有表记录的日期列(vacFrom,vacTo)之间的天求和,但不包括工作日,例如:星期一和星期二或我将通过命令参数传递的任何其他日子?

1 个答案:

答案 0 :(得分:1)

仅使用两个辅助整数变量DATEDIFF(Day,0,vacFrom)和1 + DATEDIFF(Day,0,vacTo)-我将其命名为f和t-您可以计算所有此类值。 例如,vacFrom-vacTo假期的总天数为t-f。要减去某些工作日的数量,可以使用两个整数除法的结果之差来计算它们的数量。例如,t / 7-f / 7是间隔中的星期天数。通常,间隔中的“ x天”数可以计算为差异

(t-x)/7 - (f-x)/7

其中(取模7):

  • x = 0(星期日)
  • x = 1(星期一)
  • x = 2(星期二),
  • x = 3(星期三)
  • x = 4(星期四)
  • x = 5(星期五)和
  • x = 6(星期六)(我更喜欢x = -1)。

之所以可行,是因为上面的DATEDIFF表达式中使用的“日期0”是星期一(不取决于某些区域设置)。 因此,假期间隔中的天数(不包括周日和周六)是

(t - f) - (t/7 - f/7) - ((t+1)/7 - (f+1)/7)

您将必须在这些值上构建一个SUM(如您在示例中所做的那样),并希望按某些userID(不是)进行分组。

以下问题,如果您想排除星期一和星期四(在上面的列表中为1和4),并且希望将这两个(当然,课程的模数不得等于7)作为查询的参数,您可以使用以下T-SQL代码(您可以改为使用存储过程或表值函数来传递两个参数):

DECLARE @par1 int = 1  -- Mondays
      , @par2 int = 4; -- Thursdays

SELECT userID
  , SUM((aux.t - aux.f)
      - ((aux.t-@par1)/7 - (aux.f-@par1)/7)
      - ((aux.t-@par2)/7 - (aux.f-@par2)/7)
    ) AS vacDays
FROM MS_users_vacations
  CROSS APPLY (
    VALUES (DATEDIFF(Day, 0, vacFrom), 1+DATEDIFF(Day, 0, vacTo))
  ) aux (f, t)
WHERE YEAR(vacFrom) = 2018
GROUP BY userID;

您还可以仅排除一个工作日,甚至不超过两个工作日,但如果减去所有7个可能的差异,结果将为0。:-)