【问题标题】:How to count date difference excluding weekend and holidays in MySQL如何在MySQL中计算不包括周末和节假日的日期差异
【发布时间】:2012-04-26 09:38:39
【问题描述】:

我需要计算两个日期之间的天数(工作日),不包括周末(最重要的)和节假日

SELECT DATEDIFF(end_date, start_date) from accounts

但是,我不知道我应该如何在 MySQL 中做到这一点,我找到了这篇文章 Count days between two dates, excluding weekends (MySQL only)。我无法弄清楚如何在 mysql 中进行功能查询,您能否提供一些有关如何使用 mysql 查询来实现这一点的信息。如果我遗漏了什么,请告诉我。

[编辑]

CREATE TABLE `candidatecase` (
  `ID` int(11) NOT NULL AUTO_INCREMENT COMMENT 'Unique ID',
  `CreatedBy` int(11) NOT NULL,
  `UseraccountID` int(11) NOT NULL COMMENT 'User Account ID',
  `ReportReadyID` int(11) DEFAULT NULL COMMENT 'Report Ready ID',
  `DateCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT 'Date Created',
  `InitiatedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Initiated',
  `ActualCompletedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Completed Case',
  `ProjectedCompletedDate` timestamp NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Date Projected Finish',
  `CheckpackagesID` int(11) DEFAULT NULL COMMENT 'Default Check Package Auto Assign Once Initiate Start',
  `Alacartepackage1` int(11) DEFAULT NULL COMMENT 'Ala carte Request #2',
  `Alacartepackage2` int(11) DEFAULT NULL COMMENT 'Ala carte Request #3',
  `OperatorID` int(11) NOT NULL COMMENT 'User Account - Operator',
  `Status` int(11) NOT NULL COMMENT 'Status',
  `caseRef` varchar(100) NOT NULL,
  PRIMARY KEY (`ID`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=293 ;

--
-- Dumping data for table `candidatecase`
--

INSERT INTO `candidatecase` (`ID`, `CreatedBy`, `UseraccountID`, `ReportReadyID`, `DateCreated`, `InitiatedDate`, `ActualCompletedDate`, `ProjectedCompletedDate`, `CheckpackagesID`, `Alacartepackage1`, `Alacartepackage2`, `OperatorID`, `Status`, `caseRef`) VALUES
(1, 43, 70, NULL, '2011-07-22 02:29:31', '2011-07-07 07:27:44', '2011-07-22 02:29:31', '2011-07-17 06:53:52', 11, NULL, NULL, 44, 6, ''),
(2, 43, 74, NULL, '2012-04-03 04:17:15', '2011-07-11 07:07:23', '2011-07-13 05:32:58', '2011-07-21 07:01:34', 20, 0, 0, 51, 0, ''),
(3, 43, 75, NULL, '2011-07-29 04:10:07', '2011-07-11 07:27:12', '2011-07-29 04:10:07', '2011-07-21 07:02:14', 20, NULL, NULL, 45, 6, ''),
(4, 43, 78, NULL, '2011-07-18 03:32:27', '2011-07-11 07:51:31', '2011-07-13 02:18:34', '2011-07-21 07:37:53', 20, NULL, NULL, 45, 6, ''),
(5, 43, 76, NULL, '2011-07-29 04:09:19', '2011-07-11 07:51:11', '2011-07-29 04:09:19', '2011-07-21 07:38:30', 20, NULL, NULL, 45, 6, ''),
(6, 43, 77, NULL, '2011-07-18 03:32:49', '2011-07-11 07:51:34', '2011-07-18 02:18:46', '2011-07-21 07:39:00', 20, NULL, NULL, 45, 6, ''),
(7, 43, 79, NULL, '2011-07-18 03:33:02', '2011-07-11 07:53:24', '2011-07-18 01:50:12', '2011-07-21 07:42:57', 20, NULL, NULL, 45, 6, ''),
(8, 43, 80, NULL, '2011-07-29 04:10:38', '2011-07-11 07:53:58', '2011-07-29 04:10:38', '2011-07-21 07:43:14', 20, NULL, NULL, 45, 6, ''),
(9, 43, 81, NULL, '2011-07-18 03:31:54', '2011-07-11 07:53:49', '2011-07-13 02:17:02', '2011-07-21 07:43:43', 20, NULL, NULL, 45, 6, ''),
(11, 43, 88, NULL, '2011-07-18 03:15:53', '2011-07-13 04:57:38', '2011-07-15 08:57:15', '2011-07-23 04:39:14', 12, NULL, NULL, 44, 6, ''),
(13, 43, 90, NULL, '2011-07-26 07:39:24', '2011-07-13 12:16:48', '2011-07-26 07:39:24', '2011-07-23 12:13:50', 15, NULL, NULL, 51, 6, ''),
(63, 43, 176, NULL, '2011-09-13 08:23:13', '2011-08-26 10:00:32', '2011-09-13 08:23:13', '2011-09-05 09:58:47', 41, NULL, NULL, 45, 6, ''),
(62, 43, 174, NULL, '2011-08-24 03:54:30', '2011-08-24 03:53:13', '2011-08-24 03:54:30', '2011-08-29 03:52:48', 17, NULL, NULL, 51, 6, ''),
(61, 43, 173, NULL, '2011-08-24 03:55:05', '2011-08-24 03:53:39', '2011-08-24 03:55:05', '2011-08-29 03:52:36', 17, NULL, NULL, 51, 6, ''),
(60, 43, 172, NULL, '2011-08-24 03:22:41', '2011-08-24 03:21:50', '2011-08-24 03:22:41', '2011-08-29 03:21:11', 17, NULL, NULL, 51, 6, ''),
(59, 43, 171, NULL, '2011-08-24 03:23:19', '2011-08-24 03:22:00', '2011-08-24 03:23:19', '2011-08-29 03:20:57', 17, NULL, NULL, 51, 6, '');

【问题讨论】:

  • 是否必须全部在mysql中完成?您可能需要一张单独的桌子,上面有假期日期?以及查询中的某种 where 子句。
  • 是的,我有假期表,是的,它必须在 mysql 中完成。

标签: mysql sql


【解决方案1】:

创建一个表,其中包含未来 100 年的所有周末和节假日。

您需要能够指定一天是什么时候是“假期”,因为目前还没有人知道 2052 年的假期是什么,无论如何您现在无法做出准确的函数。只需在每年知道假期时更新您的非工作日表(但您总是会知道周末)。

那么你的查询变成:

SELECT DATEFIFF(end_date, start_date) - COALESCE((SELECT COUNT(1) FROM nonWorkDays WHERE nonWorkDays.date BETWEEN start_date AND end_date), 0)
FROM accounts

如果你真的需要编写一个DATEDIFFWITHOUTWEEKENDSORHOLIDAYS 函数,那么只需使用上面的方法并创建一个函数(关于如何在每个 RDBMS 中创建函数的资源很多).. 一定要给它一个更好的名字。 ^_^

您需要解决的一件事是我认为上面某处缺少 +1,例如 DATEDIFF(today, today) 如果今天是周末将返回 -1 而不是返回 0。

【讨论】:

    【解决方案2】:

    你可能想试试这个:

    1. 统计工作日数(取自here)

      SELECT 5 * (DATEDIFF('2012-12-31', '2012-01-01') DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY('2012-01-01') + WEEKDAY('2012-12-31') + 1, 1)

      这使您在 2012 年有 261 个工作日。

    2. 现在您需要知道不是周末的假期

      SELECT COUNT(*) FROM holidays WHERE DAYOFWEEK(holiday) < 6

      结果取决于您的假期表。

    3. 我们需要在一个查询中得到它:

      SELECT 5 * (DATEDIFF('2012-12-31', '2012-01-01') DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY('2012-01-01') + WEEKDAY('2012-12-31') + 1, 1) - (SELECT COUNT(*) FROM holidays WHERE DAYOFWEEK(holiday) < 6)

      应该就是这个了。

    编辑:请注意,这只有在您的结束日期早于开始日期时才能正常工作。

    【讨论】:

    • 这工作正常,但我只是得到负输出,例如 -14 而不是 14。
    • 您还必须将假期的子查询限制在您在主查询中查找的日期范围内。 (SELECT COUNT(*) FROM holidays ... WHERE date BETWEEN X AND Y)。并且您的假期表中不应有重复的项目(或将子查询更改为无法识别它们)。
    • 我字段成功,我来发脚本
    • 我可以看到您的一个问题是,在您的数据中,您的 created 日期高于 completed 日期,这会使您的结果变为负数。老实说,我不知道我的答案中的查询是否为您返回了正确的值,您需要检查一下。如果你想要积极的结果,你可能想要使用 MySQLs abs() 函数。
    • DAYOFWEEK() 周日返回 1,周六返回 7,所以我认为假期的条件应该是 DAYOFWEEK(holiday_date) between 2 and 6。
    【解决方案3】:

    这样的事情可能会奏效。将所有假日日期和周末日期添加到表中。

    SELECT 
      DATEDIFF(end_date, start_date) 
    FROM table
    WHERE date NOT IN (SELECT date FROM holidaydatestable )
    

    【讨论】:

    • 但是,你怎么知道周末的日期,我猜这是不可能的
    • 您将周末日期添加到holidaydatestable中
    • 你怎么知道前 10 年的整个周末
    【解决方案4】:

    试试这个代码,这将计算不包括周末的天数

     SELECT
           (DATEDIFF(dd, @StartDate, @EndDate)+1)
          -(DATEDIFF(wk, @StartDate, @EndDate) * 2)
    from test_tbl where date NOT IN (SELECT date FROM holidaydatestable )
    

    【讨论】:

      【解决方案5】:

      创建一个函数,在日期之间进行一段时间循环,当它不是星期六或星期日时增加天数。

      【讨论】:

      • 是否可以在不使用循环的情况下实现这一点,我不知道这就是我在这一点上堆叠的原因。如果我可以只使用某些库来计算它,我会很有趣吗?
      猜你喜欢
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多