小智 66
这个表达 -
5 * (DATEDIFF(@E, @S) DIV 7) + MID('0123444401233334012222340111123400012345001234550', 7 * WEEKDAY(@S) + WEEKDAY(@E) + 1, 1)
Run Code Online (Sandbox Code Playgroud)
计算开始日期@S和结束日期@E之间的工作日数.
假设结束日期(@E)不在开始日期之前(@S).与DATEDIFF兼容,因为相同的开始日期和结束日期为零工作日.忽略假期.
数字串的构造如下.创建一个开始日和结束日的表,行必须以星期一(WEEKDAY 0)开头,列也必须以星期一开始.从左上角到右下角填写对角线,全部为0(即星期一到星期一,星期二和星期二之间有0个工作日,等等).对于每天从对角线开始(必须始终为0)并填写右侧的列,一次一天.如果您在周末(非工作日)列登陆,则工作日数不会更改,而是从左侧开始.否则,工作日数会增加一个.当你到达行循环的末尾回到同一行的开头并继续直到你再次到达对角线.然后继续下一行.
例如,假设周六和周日不是工作日 -
| M T W T F S S
-|--------------
M| 0 1 2 3 4 4 4
T| 4 0 1 2 3 3 3
W| 3 4 0 1 2 2 2
T| 2 3 4 0 1 1 1
F| 1 2 3 4 0 0 0
S| 1 2 3 4 5 0 0
S| 1 2 3 4 5 5 0
Run Code Online (Sandbox Code Playgroud)
然后将表中的49个值连接到字符串中.
如果您发现任何错误,请告诉我.
-Edit改进表:
| M T W T F S S
-|--------------
M| 0 1 2 3 4 4 4
T| 4 0 1 2 3 3 3
W| 3 4 0 1 2 2 2
T| 2 3 4 0 1 1 1
F| 1 2 3 4 0 0 0
S| 0 1 2 3 4 0 0
S| 0 1 2 3 4 4 0
Run Code Online (Sandbox Code Playgroud)
改进的字符串:'0123444401233334012222340111123400001234000123440'
表达改善:
5 * (DATEDIFF(@E, @S) DIV 7) + MID('0123444401233334012222340111123400001234000123440', 7 * WEEKDAY(@S) + WEEKDAY(@E) + 1, 1)
Run Code Online (Sandbox Code Playgroud)
Bry*_*hty 14
该解决方案使用与Rodger基本相同的方法,除了生成矩阵的方法要复杂得多.注意:此解决方案的此输出与NETWORKDAYS不兼容.
与Rodger的解决方案一样,这可以计算开始日期(@S)和结束日期(@E)之间的工作日数,而无需定义存储过程.它假定结束日期不在开始日期之前.使用相同的开始和结束日期将产生0.不考虑假期.
这与Rodger的解决方案之间的主要区别在于矩阵和结果的数字串是由一个我没有包含的复杂算法构造的.该算法的输出由单元测试验证(参见下面的测试输入和输出).在矩阵中,任何给定的x和y值对(WEEKDAY(@S)和WEEKDAY(@E)的交集产生两个值之间的工作日差异.分配顺序实际上并不重要,因为两者被加在一起绘制位置.
营业日为周一至周五
| M T W T F S S
-|--------------
M| 0 1 2 3 4 5 5
T| 5 0 1 2 3 4 4
W| 4 5 0 1 2 3 3
T| 3 4 5 0 1 2 2
F| 2 3 4 5 0 1 1
S| 0 1 2 3 4 0 0
S| 0 1 2 3 4 5 0
Run Code Online (Sandbox Code Playgroud)
表中的49个值连接成以下字符串:
0123455501234445012333450122234501101234000123450
Run Code Online (Sandbox Code Playgroud)
最后,正确的表达是:
5 * (DATEDIFF(@E, @S) DIV 7) + MID('0123455501234445012333450122234501101234000123450', 7 * WEEKDAY(@S) + WEEKDAY(@E) + 1, 1)
Run Code Online (Sandbox Code Playgroud)
我已使用此解决方案验证了以下输入和输出:
Sunday, 2012-08-26 -> Monday, 2012-08-27 = 0
Sunday, 2012-08-26 -> Sunday, 2012-09-02 = 5
Monday, 2012-08-27 -> Tuesday, 2012-08-28 = 1
Monday, 2012-08-27 -> Monday, 2012-09-10 = 10
Monday, 2012-08-27 -> Monday, 2012-09-17 = 15
Monday, 2012-08-27 -> Tuesday, 2012-09-18 = 16
Monday, 2012-08-27 -> Monday, 2012-09-24 = 20
Monday, 2012-08-27 -> Monday, 2012-10-01 = 25
Tuesday, 2012-08-28 -> Wednesday, 2012-08-29 = 1
Wednesday, 2012-08-29 -> Thursday, 2012-08-30 = 1
Thursday, 2012-08-30 -> Friday, 2012-08-31 = 1
Friday, 2012-08-31 -> Saturday, 2012-09-01 = 1
Saturday, 2012-09-01 -> Sunday, 2012-09-02 = 0
Sunday, 2012-09-02 -> Monday, 2012-09-03 = 0
Monday, 2012-09-03 -> Tuesday, 2012-09-04 = 1
Tuesday, 2012-09-04 -> Wednesday, 2012-09-05 = 1
Wednesday, 2012-09-05 -> Thursday, 2012-09-06 = 1
Thursday, 2012-09-06 -> Friday, 2012-09-07 = 1
Friday, 2012-09-07 -> Saturday, 2012-09-08 = 1
Saturday, 2012-09-08 -> Sunday, 2012-09-09 = 0
Monday, 2012-09-24 -> Sunday, 2012-10-07 = 10
Saturday, 2012-08-25 -> Saturday, 2012-08-25 = 0
Saturday, 2012-08-25 -> Sunday, 2012-08-26 = 0
Saturday, 2012-08-25 -> Monday, 2012-08-27 = 0
Saturday, 2012-08-25 -> Tuesday, 2012-08-28 = 1
Saturday, 2012-08-25 -> Wednesday, 2012-08-29 = 2
Saturday, 2012-08-25 -> Thursday, 2012-08-30 = 3
Saturday, 2012-08-25 -> Friday, 2012-08-31 = 4
Saturday, 2012-08-25 -> Sunday, 2012-09-02 = 0
Monday, 2012-08-27 -> Monday, 2012-08-27 = 0
Monday, 2012-08-27 -> Tuesday, 2012-08-28 = 1
Monday, 2012-08-27 -> Wednesday, 2012-08-29 = 2
Monday, 2012-08-27 -> Thursday, 2012-08-30 = 3
Monday, 2012-08-27 -> Friday, 2012-08-31 = 4
Monday, 2012-08-27 -> Saturday, 2012-09-01 = 5
Monday, 2012-08-27 -> Sunday, 2012-09-02 = 5
Run Code Online (Sandbox Code Playgroud)
Tom*_*m H 13
由于您需要在某处跟踪假期,因此Calendar表似乎合适:
CREATE TABLE Calendar
(
calendar_date DATETIME NOT NULL,
is_holiday BIT NOT NULL,
is_weekend BIT NOT NULL,
CONSTRAINT PK_Calendar PRIMARY KEY CLUSTERED (calendar_date)
)
Run Code Online (Sandbox Code Playgroud)
当然,您需要在应用程序中使用的任何时间段填充所有日期.由于一年只有365天(或366天),从1900年到2100年并不是什么大不了的事.只需确保加载所有日期,而不仅仅是假期.
那时候你需要的查询变得微不足道:
SELECT
COUNT(*)
FROM
Calendar
WHERE
calendar_date BETWEEN '2009-01-01' AND '2009-10-01' AND
is_holiday = 0 AND
is_weekend = 0
Run Code Online (Sandbox Code Playgroud)
警告:我主要使用MS SQL并且长时间没有使用MySQL,所以你可能需要调整上面的内容.例如,我甚至不记得MySQL是否具有BIT数据类型.
Cav*_*man 10
提议的字符串可能是错的吗?
DATEDIFF(from,to)排除'to'.这个字符串应该是这样的:
星期一 - >星期五= {星期一,土族,星期三,星期四} = 4
星期一 - >星期六= {星期一,涂,星期三,星期五,星期五} = 5
星期二 - >星期一= {涂,星期三,星期五,星期五,跳过星期六,跳过太阳,星期一被排除} = 4
等等
拟议矩阵:
| M T W T F S S
-|--------------
M| 0 1 2 3 4 5 5
T| 4 0 1 2 3 4 4
W| 3 4 0 1 2 3 3
T| 2 3 4 0 1 2 2
F| 1 2 3 4 0 1 1
S| 0 1 2 3 4 0 0
S| 0 1 2 3 4 5 0
Run Code Online (Sandbox Code Playgroud)
字符串:'0123455401234434012332340122123401101234000123450'
我错过了什么吗?:)
仅供进一步参考.以上都不适用于我,但@Jeff Kooser的修改版本:
SELECT (DATEDIFF(date_end, date_start)) -
((WEEK(date_end) - WEEK(date_start)) * 2) -
(case when weekday(date_end) = 6 then 1 else 0 end) -
(case when weekday(date_start) = 5 then 1 else 0 end) -
(SELECT COUNT(*) FROM holidays WHERE holiday>=date_start and holiday<=data_end)
Run Code Online (Sandbox Code Playgroud)
小智 5
给定一个月的第一天,这将返回该月内的工作日数。在 MySQL 中。没有存储过程。
SELECT (DATEDIFF(LAST_DAY(?),?) + 1) -
((WEEK(LAST_DAY(?)) - WEEK(?)) * 2) -
(case when weekday(?) = 6 then 1 else 0 end) -
(case when weekday(LAST_DAY(?)) = 5 then 1 else 0 end)
Run Code Online (Sandbox Code Playgroud)
小智 5
SELECT 5* (DATEDIFF(u.EndDate, u.StartDate) DIV 7) + MID('1234555512344445123333451222234511112345001234550', 7 * WEEKDAY(u.StartDate) + WEEKDAY(u.EndDate) + 1, 1)
Run Code Online (Sandbox Code Playgroud)
这时您需要考虑以下情况:
1) 如果开始日期 = 结束日期,持续时间 = 1 ,同样..
我使用投票最多的答案中提到的逻辑计算了字符串,并得到了我需要的结果。
归档时间: |
|
查看次数: |
64893 次 |
最近记录: |