这比看起来更难。我需要一个函数来计算日期范围内给定工作日的数字。我不想要任何循环或递归 SQL。有数百万个例子就是这样做的。我需要一个快速的计算函数。
函数的输入将是工作日、从数据、到日期
-- counting fridays
set datefirst 1
SELECT dbo.f_countweekdays(5, '2011-07-01', '2011-07-31'),
dbo.f_countweekdays(5, '2011-07-08', '2011-07-15'),
dbo.f_countweekdays(5, '2011-07-09', '2011-07-15'),
dbo.f_countweekdays(5, '2011-07-09', '2011-07-14')
预期结果:
5, 2, 1, 0
最佳答案
@Mikael Eriksson 有一个绝妙的主意,但他的实现似乎有点过于复杂。
这是我想出的(我想强调的是 它基于 solution by @Mikael ,主要功劳应该归于谁):
ALTER FUNCTION dbo.f_countweekdays (@Dow int, @StartDate datetime, @EndDate datetime)
RETURNS int
AS BEGIN
RETURN (
SELECT
DATEDIFF(wk, @StartDate, @EndDate)
- CASE WHEN DATEPART(dw, @StartDate) > @Dow THEN 1 ELSE 0 END
- CASE WHEN DATEPART(dw, @EndDate) < @Dow THEN 1 ELSE 0 END
+ 1
)
END
更新
正如 Mikael 在他的回答的评论线程中正确指出的那样,为了使上述解决方案正常工作,必须将 DATEFIRST 设置设置为
7
(星期日)。虽然我找不到这个文档,但快速测试显示 DATEDIFF(wk)
忽略了实际的 DATEFIRST 设置并且确实返回了几周的差异,就好像 DATEFIRST 总是设置为 7 一样。同时 DATEPART(dw)
确实尊重 DATEFIRST
,所以 DATEFIRST 设置为7 以外的值这两个函数返回相互不一致的结果。因此,必须修改上述脚本,以便在计算
DATEDIFF(wk)
时考虑 DATEFIRST 设置的不同值。令人高兴的是,在我看来,修复似乎并没有使解决方案比以前复杂得多。不过,请自行判断:ALTER FUNCTION dbo.f_countweekdays (@Dow int, @StartDate datetime, @EndDate datetime)
RETURNS int
AS BEGIN
RETURN (
SELECT
DATEDIFF(wk, DATEADD(DAY, -@@DATEFIRST, @StartDate),
DATEADD(DAY, -@@DATEFIRST, @EndDate))
- CASE WHEN DATEPART(dw, @StartDate) > @Dow THEN 1 ELSE 0 END
- CASE WHEN DATEPART(dw, @EndDate) < @Dow THEN 1 ELSE 0 END
+ 1
)
END
编辑: 两个
-@@DATEFIRST % 7
条目都已简化为 -@@DATEFIRST
,正如有人建议的 here 。