[英]MySQL Function to add a number of working days to a DATETIME
I need a MySQL Function that will allow me to pass a number of working days (Monday - Friday) and a start DATE or DATETIME (doesn't matter for my implementation), and have it return a new DATE or DATETIME that many work days in the future. 我需要一个MySQL函数,该函数将允许我经过多个工作日(星期一至星期五),并开始一个DATE或DATETIME(与我的实现无关紧要),并使其返回多个工作日的新DATE或DATETIME。在将来。
Example: SELECT AddWorkDays(10, "2013-09-01")
returns "2013-09-16" assuming "2013-09-01" is a Monday. 示例:假设“ 2013-09-01”是星期一
SELECT AddWorkDays(10, "2013-09-01")
将返回“ 2013-09-16”。
Similarly: SELECT AddWorkDays(-10, "2013-09-16")
returns "2013-09-01" 同样:
SELECT AddWorkDays(-10, "2013-09-16")
返回“ 2013-09-01”
I found this function for an MSSQL database (I think) that is exactly what I need except its not in MySQL. 我找到了我所需要的MSSQL数据库的此功能(我认为),除了MySQL中没有。 I tried to manually convert it into MySQL syntax and got about this far:
我试图将其手动转换为MySQL语法,到目前为止:
DROP FUNCTION IF EXISTS AddWorkDays;
DELIMITER $$
CREATE FUNCTION AddWorkDays
(
WorkingDays INT,
StartDate DATE
)
RETURNS DATE
BEGIN
DECLARE Count INT;
DECLARE i INT;
DECLARE NewDate DATE;
SET Count = 0;
SET i = 0;
WHILE (i < WorkingDays) DO
BEGIN
SET Count = Count + 1;
SET i = i + 1;
WHILE DAYOFWEEK(ADDDATE(StartDate, Count)) IN (1,7) DO
BEGIN
SET Count = Count + 1;
END;
END WHILE;
END;
END WHILE;
SET NewDate = ADDDATE(StartDate, Count);
RETURN NewDate;
END;
$$
DELIMITER ;
I end up getting an error: 我最终得到一个错误:
Error 1415: Not allowed to return a result set from a function
I can't seem to figure out where exactly it is trying to return a result set. 我似乎无法弄清楚它试图返回结果集的确切位置。
Is there an error in my syntax? 我的语法有错误吗? Are there any better solutions?
有更好的解决方案吗?
Thanks! 谢谢!
EDIT 编辑
It appears MySQL doesn't have a DATEPART or DATEADD function. 看来MySQL没有DATEPART或DATEADD函数。 I see in the documentation that they have ADDDATE and DAYOFWEEK.
我在文档中看到它们具有ADDDATE和DAYOFWEEK。 Updated the code to represent this.
更新了代码以表示这一点。 I also changed the SELECT statements to SET (Makes sense now why I was getting the original error)
我还将SELECT语句更改为SET(现在理解为什么我得到了原始错误)
As a result I get a new error when attempting to run a query using the function via CF 结果,尝试通过CF使用该函数运行查询时收到新错误
[Table (rows 1 columns ADDWORKDAYS(10,"2013-09-01")): [ADDWORKDAYS(10,"2013-09-01"): coldfusion.sql.QueryColumn@7a010] ] is not indexable by ADDWORKDAYS(10
This is new function with mysql syntax: 这是mysql语法的新功能:
DROP FUNCTION IF EXISTS AddWorkDays;
DELIMITER $$
CREATE FUNCTION AddWorkDays
(
WorkingDays INT,
StartDate DATETIME
)
RETURNS DATETIME
BEGIN
DECLARE Count INT;
DECLARE i INT;
DECLARE NewDate DATETIME;
SET Count = 0;
SET i = 0;
WHILE (i < WorkingDays) DO
BEGIN
SELECT Count + 1 INTO Count;
SELECT i + 1 INTO i;
WHILE DAYOFWEEK(DATE_ADD(StartDate,INTERVAL Count DAY)) IN (1,7) DO
BEGIN
SELECT Count + 1 INTO Count;
END;
END WHILE;
END;
END WHILE;
SELECT DATE_ADD(StartDate,INTERVAL Count DAY) INTO NewDate;
RETURN NewDate;
END;
$$
DELIMITER ;
This implementation is a bit more efficient then the accepted answer (probably not important), but also works for negative business days (was important for me). 此实现比接受的答案(可能不重要)要有效一些,但在负工作日也可以使用(对我来说很重要)。
The basic idea was every 5 days converts to 7 days, then you might need to adjust by adding or subtracting 2 days if the (days % 5) + the start day of the week is not a week day. 基本思想是每5天转换为7天,如果(天数%5)+一周的开始日期不是一周的一天,则可能需要通过增加或减去2天来进行调整。
DROP FUNCTION IF EXISTS AddBusDays;
DELIMITER $$
CREATE FUNCTION AddBusDays
(
WorkingDays INT,
UtcStartDate DATETIME,
TZ VARCHAR(1024)
)
RETURNS DATETIME
BEGIN
DECLARE RealOffset INT;
DECLARE StartDate DATETIME;
DECLARE Adjustment INT;
SELECT CONVERT_TZ(UtcStartDate, 'UTC', TZ) into StartDate;
select case when WorkingDays >=0 then 2 else -2 end into Adjustment;
select
case when (WorkingDays >= 0 AND DAYOFWEEK(StartDate) + (WorkingDays % 5) > 6) OR (WorkingDays < 0 AND DAYOFWEEK(StartDate) + (WorkingDays % 5) < 2)
then (WorkingDays % 5) + Adjustment + (WorkingDays DIV 5) * 7
else WorkingDays % 5 + (WorkingDays DIV 5) * 7
end into RealOffset;
return CONVERT_TZ(date(adddate(StartDate, RealOffset)), TZ, 'UTC');
END;
$$
DELIMITER ;
-- This is exact query which adds no of business days to date (Exclude Saturday and Sunday)
DROP FUNCTION IF EXISTS DateAddBusiness;
DELIMITER ||
CREATE FUNCTION DateAddBusiness(mydate DATE, numday INT)
RETURNS DATE
DETERMINISTIC
COMMENT 'Adds business days between two dates'
BEGIN
DECLARE num_week INT DEFAULT 0;
DECLARE num_day INT DEFAULT 0;
DECLARE adj INT DEFAULT 0;
DECLARE total INT DEFAULT 0;
SET num_week = numday DIV 5;
SET num_day = MOD(numday, 5);
IF (DAYOFWEEK(mydate)=6 || DAYOFWEEK(mydate)=5 || DAYOFWEEK(mydate)=4 ) then
SET adj = 2;
END IF;
IF (DAYOFWEEK(mydate)=7 ) then
SET adj = 1;
END IF;
SET total = adj + num_day;
RETURN DATE_ADD(mydate, INTERVAL total DAY);
END
||
DELIMITER ;
-- Unit testing queries
select DateAddBusiness("2015-10-19","3") // 22
select DateAddBusiness("2015-10-20","3") // 23
select DateAddBusiness("2015-10-21","3") // 26
select DateAddBusiness("2015-10-22","3") // 27
select DateAddBusiness("2015-10-23","3") // 28
select DateAddBusiness("2015-10-24","3") //28
select DateAddBusiness("2015-10-25","3") //28
select DateAddBusiness("2015-10-26","3") //29
I modified the version given here to accept both positive and negative days. 我修改了此处给出的版本,以接受正数和负数的日子。 None of the other answers were doing it for me so this is the most efficient solution I came up with.
没有其他答案对我有用,因此这是我想到的最有效的解决方案。
DROP FUNCTION IF EXISTS WORKDAY_ADD;
DELIMITER &&
CREATE FUNCTION WORKDAY_ADD(mydate DATE, numday INT) RETURNS DATE
BEGIN
DECLARE num_week INT DEFAULT 0;
DECLARE num_day INT DEFAULT 0;
DECLARE adj INT DEFAULT 0;
DECLARE total INT DEFAULT 0;
SET num_week = ABS(numday DIV 5);
SET num_day = MOD(numday, 5);
IF (WEEKDAY(DATE_ADD(mydate, INTERVAL num_day DAY)) >= 5) THEN
SET adj = 2;
END IF;
SET total = (num_week * 7 + adj + ABS(num_day));
IF numday < 0 THEN
SET total = total * -1;
END IF;
RETURN DATE_ADD(mydate, INTERVAL total DAY);
END&&
DELIMITER ;
Add five business days: SELECT WORKDAY_ADD('2016-02-18', 5)
添加五个工作日:
SELECT WORKDAY_ADD('2016-02-18', 5)
Subtract two business days: SELECT WORKDAY_ADD('2016-02-18', -2)
减去两个工作日:
SELECT WORKDAY_ADD('2016-02-18', -2)
CREATE FUNCTION `WORKDAY_ADD`(exp_date DATE, days_to_add SMALLINT)
RETURNS date
DETERMINISTIC
BEGIN
DECLARE res_date DATE;
DECLARE day_count TINYINT;
SET res_date = date_add(exp_date, INTERVAL 1 DAY);
IF DAYNAME(res_date)='Monday' OR DAYNAME(res_date)='Tuesday' OR DAYNAME(res_date)='Wednesday' THEN
SET res_date = date_add(exp_date, INTERVAL days_to_add DAY);
ELSEIF DAYNAME(res_date)='Thursday' OR DAYNAME(res_date)='Friday' OR DAYNAME(res_date)='Saturday' THEN
SET res_date = date_add(exp_date, INTERVAL days_to_add+2 DAY);
ELSEIF DAYNAME(res_date)='Sunday' THEN
SET res_date = date_add(exp_date, INTERVAL days_to_add+1 DAY);
END IF;
RETURN res_date;
END;
FUNCTION `WORKDAY_ADD`(mydate DATE, numday INT) RETURNS date
BEGIN
DECLARE num_day INT DEFAULT 0;
DECLARE adj INT DEFAULT 0;
DECLARE total INT DEFAULT 0;
SET num_week = ABS(numday DIV 5);
SET num_day = MOD(numday, 5);
IF numday > 0 and (WEEKDAY(DATE_ADD(mydate, INTERVAL num_day DAY)) < WEEKDAY(mydate)) THEN
SET adj = 2;
END IF;
IF numday < 0 and (WEEKDAY(DATE_ADD(mydate, INTERVAL num_day DAY)) > WEEKDAY(mydate)) THEN
SET adj = 2;
END IF;
SET total = (num_week * 7 + adj + ABS(num_day));
IF numday < 0 THEN
SET total = total * -1;
END IF;
RETURN DATE_ADD(mydate, INTERVAL total DAY);
END
Hi all, needed a formula that would go backwards and forwards. 大家好,我们需要一个可以前后移动的公式。 I used one above but spotted an error.
我在上面使用了一个,但发现一个错误。 I have corrected it now and the formula is working well.
我现在已对其进行更正,该公式运行良好。
FUNCTION `Addworkday`(workday int(5),dt date) RETURNS date
begin
declare count int;
declare i int;
declare y date;
set count=0;
while count<workday do
set count=count+1;
set dt=date_add(dt,interval 1 day);
while dayofweek(dt) in (1,7) do
set dt=date_add(dt,interval 1 day);
end while;
end while;
return dt;
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.