我目前在我的SQL数据库中有一个函数,它在一个日期中添加了一定的工作日,例如,如果您输入的是星期四的日期并添加两天,它将返回下一个星期一的日期.我对任何假期都不感到烦恼,只有周末才被排除在外.
问题是,这当前使用while循环完成,并且它似乎大大减慢了在生成表时使用它的存储过程.有没有人知道是否有任何方法可以在没有while循环或游标的情况下执行此计算?
仅供参考,这是当前的功能:
ALTER FUNCTION [dbo].[AddWorkDaysToDate]
(
@fromDate datetime,
@daysToAdd int
)
RETURNS datetime
AS
BEGIN
DECLARE @toDate datetime
DECLARE @daysAdded integer
-- add the days, ignoring weekends (i.e. add working days)
set @daysAdded = 1
set @toDate = @fromDate
while @daysAdded <= @daysToAdd
begin
-- add a day to the to date
set @toDate = DateAdd(day, 1, @toDate)
-- only move on a day if we've hit a week day
if (DatePart(dw, @toDate) != 1) and (DatePart(dw, @toDate) != 7)
begin
set @daysAdded = @daysAdded + 1
end
end
RETURN @toDate
END
Run Code Online (Sandbox Code Playgroud)
小智 31
如果有人在寻找TSQL解决方案,那就更好了.没有循环,没有表格,没有案例陈述和负面作品.谁能打败那个?
CREATE FUNCTION[dbo].[AddBusinessDays](@Date date,@n INT)
RETURNS DATE AS
BEGIN
DECLARE @d INT;SET @d=4-SIGN(@n)*(4-DATEPART(DW,@Date));
RETURN DATEADD(D,@n+((ABS(@n)+@d-2)/5)*2*SIGN(@n)-@d/7,@Date);
END
Run Code Online (Sandbox Code Playgroud)
Dam*_*ver 16
这个答案自被接受以来已经有了很大的改变,因为原来是错的.我对新查询更有信心,但它并不依赖于DATEFIRST
我认为这应该涵盖它:
declare @fromDate datetime
declare @daysToAdd int
select @fromDate = '20130123',@DaysToAdd = 4
declare @Saturday int
select @Saturday = DATEPART(weekday,'20130126')
;with Numbers as (
select 0 as n union all select 1 union all select 2 union all select 3 union all select 4
), Split as (
select @DaysToAdd%5 as PartialDays,@DaysToAdd/5 as WeeksToAdd
), WeekendCheck as (
select WeeksToAdd,PartialDays,MAX(CASE WHEN DATEPART(weekday,DATEADD(day,n.n,@fromDate))=@Saturday THEN 1 ELSE 0 END) as HitWeekend
from
Split t
left join
Numbers n
on
t.PartialDays >= n.n
group by WeeksToAdd,PartialDays
)
select DATEADD(day,WeeksToAdd*7+PartialDays+CASE WHEN HitWeekend=1 THEN 2 ELSE 0 END,@fromDate)
from WeekendCheck
Run Code Online (Sandbox Code Playgroud)
我们将时间分成若干周和一周内的几天.然后,我们使用一个小数字表来计算,如果添加这几天将导致我们打一个星期六.如果确实如此,那么我们需要再增加2天.
根据此问题接受的答案,以下用户定义函数(UDF)应该适用于所有情况 - 无论设置如何@@DateFirst.
更新:如下面的评论所示,此功能是为FromDate设计的工作日.当一个周末日作为FromDate传入时,行为是未定义的.
ALTER FUNCTION [dbo].[BusinessDaysDateAdd]
(
@FromDate datetime,
@DaysToAdd int
)
RETURNS datetime
AS
BEGIN
DECLARE @Result datetime
SET @Result = DATEADD(day, (@DaysToAdd % 5) + CASE ((@@DATEFIRST + DATEPART(weekday, @FromDate) + (@DaysToAdd % 5)) % 7)
WHEN 0 THEN 2
WHEN 1 THEN 1
ELSE 0 END, DATEADD(week, (@DaysToAdd / 5), @FromDate))
RETURN @Result
END
Run Code Online (Sandbox Code Playgroud)
这个答案基于@ ElmerMiller的答案.
它修复了来自@FistOfFury的星期日评论的负值
如果传入的日期是星期日,则负值不起作用
来自@Damien_The_Unbeliever的DATEFIRST设置评论
但是这个确实假定了一个特定的DATEFIRST设置(7),其他一些不需要.
现在纠正的功能
CREATE FUNCTION[dbo].[AddBusinessDays](@Date DATE,@n INT)
RETURNS DATE AS
BEGIN
DECLARE @d INT,@f INT,@DW INT;
SET @f=CAST(abs(1^SIGN(DATEPART(DW, @Date)-(7-@@DATEFIRST))) AS BIT)
SET @DW=DATEPART(DW,@Date)-(7-@@DATEFIRST)*(@f^1)+@@DATEFIRST*(@f&1)
SET @d=4-SIGN(@n)*(4-@DW);
RETURN DATEADD(D,@n+((ABS(@n)+(@d%(8+SIGN(@n)))-2)/5)*2*SIGN(@n)-@d/7,@Date);
END
Run Code Online (Sandbox Code Playgroud)
您是否考虑过预先填充包含所有工作日(使用您的函数)的查找表,例如WorkingDays(int DaySequenceId,Date WorkingDate),然后您可以通过选择@fromDate的DaySequenceId来使用此表并添加@daysToAdd以获取新的工作日期.显然,此方法还有管理WorkingDays表的额外开销,但您可以使用您期望的日期范围预先填充它.另一个缺点是可以计算的工作日期只是WorkingDays表中包含的工作日期.
小智 5
*我知道这是一个旧线程,但是不久前发现了一些非常有用的东西,对其进行了修改并得到了这个。
select ((DATEADD(d,DATEDIFF(d,0,(DATEADD (d,2,@fromDate))),@numbOfDays)))*
Run Code Online (Sandbox Code Playgroud)
更新:很抱歉,我急于在单个语句中找到一段代码,并且为了避免使用函数,我在这里张贴了不正确的代码。
如果要添加的天数为7天或更少,则可以使用上述位。
为了更好的理解,我更改了带有必需参数的代码。
无论如何,我最终使用了上面提到的“内特·库克”。并将其用作一行代码。(因为我限制使用函数)
内特的密码
select(
DATEADD(day, (@days % 5) +
CASE ((@@DATEFIRST + DATEPART(weekday, GETDATE()) + (@days % 5)) % 7)
WHEN 0 THEN 2
WHEN 1 THEN 1
ELSE 0 END, DATEADD(week, (@days / 5), GETDATE()))
)
Run Code Online (Sandbox Code Playgroud)
为了扩展上面 Amine 的评论和 Nate Cook 的回答,对此的简单解决方案是:
declare @DaysToAdd int , @FromDate datetime
set @DaysToAdd=-5 --5 days prior is 3/28/14
set @FromDate='4/4/14'
select
DATEADD(day, (@DaysToAdd % 5)
+ CASE
WHEN ((@@DATEFIRST + DATEPART(weekday, @FromDate)) % 7 + (@DaysToAdd % 5)) > 6 THEN 2
ELSE 0
END
, DATEADD(week, (@DaysToAdd / 5), @FromDate))
Run Code Online (Sandbox Code Playgroud)
请注意,您可以添加或减去天数以分别在时间上前进和后退。
| 归档时间: |
|
| 查看次数: |
59847 次 |
| 最近记录: |