仅计算DATEDIFF(MySQL)中的工作日

kd3sttzy  于 2023-01-12  发布在  Mysql
关注(0)|答案(2)|浏览(190)

所以,下一个问题:'),我有下面的查询,@MatBailie提供给我在这里(再次感谢!):

SELECT
  taskname,
  employee,
  SUM(
    DATEDIFF(
      LEAST(     enddate, '2023-12-31'),
      GREATEST(startdate, '2023-01-01')
    )
    +1
  ) AS total_days,
FROM
  schedule
WHERE
  startDate <= '2023-12-31'
  AND
  endDate   >= '2023-01-01'
GROUP BY
  employee,
  taskname

这个查询会告诉我某个员工在给定的时间段内花了多少天在某个任务上,效果很好!
然而,我想做的下一件事是从 * 一些 * 任务的DATEDIFF的SUM中减去非工作日(例如,当任务在名为"activities"的引用表中具有"count_non_working_days = 0"时)。
例如,我的日程表还会记录每个员工的休假天数(休息日也被安排为任务)。但是,当然,在周末或节假日的休息日不应计入一个人一年的休息日总数。(注意,我确实考虑过只在工作日/非节假日安排休息日,但是这在我使用的调度软件中不是一个实用的选项,因为雇员请求从日期A到日期B的休假,这个请求被批准或拒绝(如果你明白我的意思,如果他们想去度假3周,他们不会提出3个假期请求,不包括周末)。
所以如果员工休假10天,这算10天,但是这个假期可能有1、2个周末,所以员工休假的天数总和应该是6、7、8天,而不是10天,而且如果有复活节星期一这样的假期(我在PHP数组中有我所有的假期日期),这也应该被减去。
我已经尝试了here提到的解决方案,但我无法让它们工作(a)因为它们在SQL Server中,(b)因为它们不允许放入假日数组,(c)也不允许根据事件类型切换减法的开关。
下面是我试图解释我在伪SQL中要做的事情:

SELECT
  taskname,
  employee,
  IF( activities.count_non_working_days=1,  
    -- Just count the days that fall in the current year: 
    SUM(
      DATEDIFF(
        LEAST(      enddate, '2023-12-31'),
        GREATEST( startdate, '2023-01-01')
      ) 
      + 1
    ) AS total_days,
    -- Subtract the amount of saturdays, sundays and holidays:
    SUM(
      DATEDIFF(
        LEAST(      enddate, '2023-12-31'),
        GREATEST( startdate, '2023-01-01')
      ) 
      - [some way of getting the amount of saturdays, sundays and holidays that fall within this date range]
      + 1
    ) AS total_days
  )
FROM
  schedule
LEFT JOIN
  activities
  ON activity.name = schedule.name
WHERE
  startDate <= '2023-12-31'
  AND
  endDate   >= '2023-01-01'
GROUP BY
  employee,
  taskname

我知道上面的查询可能在很多层面上都是错误的,但我希望它能澄清我试图做的事情。
再次感谢所有的帮助!
编辑:基本上我需要类似this的东西,但在MySQL中,最好有一个开关,根据任务类型打开或关闭减法。
编辑2:澄清:我的日程表包含所有活动,包括假日。例如,某些记录可能包括:
| 雇员|任务名|开始日期|结束日期|
| - ------|- ------|- ------|- ------|
| 安德森先生|程序设计|2023年1月2日|2023年1月6日|
| 安德森先生|程序设计|2023年1月9日|2023年1月14日|
| 安德森先生|休假|2023年1月14日|2023年1月31日|
在另一个表中,编程被定义为"count_non_working_days = 1",因为周末工作应该计算在内,而假期被定义为"count_non_working_days = 0",因为在周末休息一天不应该计入你的总休假天数。
因此,这个月的总数应说明:
安德森先生已经做了11天的编程(其中1天是在星期六)
安德森先生请了12天假(因为这段时间的两个周末不算休息日)。

6ss1mwsb

6ss1mwsb1#

创建一个日历表,其中包含每个感兴趣的日期(例如,2000-01-01到2099-01-01),并包含is_working_day等列,这些列可以设置为TRUE/FLASE或1/0。然后,您可以根据需要更新该列,并在查询中连接该表,以获取员工已登记的工作日期。
简而言之,你计算相关的日期,而不是扣除不相关的日期。

SELECT
  s.employee,
  s.taskname,
  COUNT(*)    AS total_days,
FROM
(
    schedule    AS s
  INNER JOIN
    activities  AS a
      ON  a.taskname = s.taskname
)
INNER JOIN
  calendar    AS c
    ON  c.calendar_date  >= s.startDate
    AND c.calendar_date  <= s.endDate
    AND c.is_working_day >= 1 - a.count_non_working_days 
WHERE
      c.calendar_date >= '2023-01-01'
  AND c.calendar_date <= '2023-12-31'
GROUP BY
  s.employee,
  s.taskname

然后,您的日历表还可以包含is_weekend、is_bank_holiday、is_fubar、is_amazing等标志,并且is_working_day可以是根据这些输入计算的列。

  • 关于is_working_day滤波器的说明... *
WHERE
     ( count_non_working_day = 1 AND is_working_day IN (0, 1) )
     OR
     ( count_non_working_day = 0 AND is_working_day IN (   1) )

   -- change to (1 - count_non_working_day)

   WHERE
     ( (1 - count_non_working_day) = 0 AND is_working_day IN (0, 1) )
     OR
     ( (1 - count_non_working_day) = 1 AND is_working_day IN (   1) )

   -- simplify

   WHERE
     ( (1 - count_non_working_day) <= is_working_day )
     OR
     ( (1 - count_non_working_day) <= is_working_day )
  

   -- simplify

   WHERE
     ( (1 - count_non_working_day) <= is_working_day )

演示:https://dbfiddle.uk/YAmpLmVE

emeijp43

emeijp432#

这是为了计算两个给定日期之间的所有周末,它可能会帮助您:

SELECT (
    ((WEEK('2022-12-31') - WEEK('2022-01-01')) * 2) -
    (case when weekday('2022-12-31') = 6 then 1 else 0 end) -
    (case when weekday('2022-01-01') = 5 then 1 else 0 end)
)

您还必须减去此日期范围内的假日。

相关问题