这比它看起来更难。我需要一个函数来计算日期范围内给定工作日的数量。我不想要任何循环或重复sql,有数百万个例子正在做这个,我需要一个快速的函数进行计算。
该功能的输入将是工作日,fromdata,todate
-- 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
我希望有人可以提供帮助。
答案 0 :(得分:4)
create function dbo.f_countweekdays
(
@DOW int,
@StartDate datetime,
@EndDate datetime
)
returns int
begin
return
( select datediff(wk, T2.St, T2.En) -
case when T1.SDOW > @DOW then 1 else 0 end -
case when T1.EDOW < @DOW then 1 else 0 end
from (select datepart(dw, @StartDate),
datepart(dw, @EndDate)) as T1(SDOW, EDOW)
cross apply (select dateadd(d, - T1.SDOW, @StartDate),
dateadd(d, 7 - T1.EDOW, @EndDate)) as T2(St, En))
end
答案 1 :(得分:3)
以下是我提出的内容(我想强调它基于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。
答案 2 :(得分:2)
另一种方法是良好的老式数据仓库时间维度,其中包含一个包含所有潜在日期的表格,以及您希望过滤/计算的任何有用信息:
Key ActualDate DayName IsWeekday DayNumberInYear FinancialQuarter
20110101 1 Jan 2011 Saturday 0 1 2011 Q1
20110102 2 Jan 2011 Sunday 0 2 2011 Q1
20110103 3 Jan 2011 Monday 1 3 2011 Q1
然后加入该表并过滤,例如
SELECT
COUNT(*)
FROM
date_dimension
WHERE
ActualDate BETWEEN '1 Jan 2011' AND '3 Jan 2011' AND
IsWeekday = 1
如果您在已知日期范围内进行日期分析,这可以真正加快并简化您的查询。您是否事先了解可能的日期范围是限制因素,这是否真的有用,但这是一个有用的技巧。
答案 3 :(得分:1)
这是我在尝试了很多不同的方法后想出来的。我确实花了很长时间来解决它,当我发布问题时,我还在努力解决它。我决定将它作为答案发布,因为自学习徽章,虽然我从来没有得到超过2分的答案。
alter function dbo.f_countweekdays
( @day int, @fromdate datetime, @todate datetime )
returns int
begin
RETURN (SELECT datediff(day, @fromdate, dateadd(week,datediff(week,0,@todate - 1) +
CASE WHEN datepart(weekday,@todate) < @day THEN 0 ELSE 1 END,0) + @day - 1) / 7)
end