Updating table with business day and calendar day

岁酱吖の 提交于 2019-12-06 06:31:06

here you go. This recursive CTE will give you the BDs for the whole month:

declare @forwhichdate datetime
set @forwhichdate ='20170401'
;with bd as(
select 
DATEADD(DAY,
CASE
    (DATEPART(WEEKDAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, @forwhichdate), 0)) + @@DATEFIRST - 1) % 7
    WHEN 6 THEN 2 
    WHEN 7 THEN 1
    ELSE 0
END,
DATEADD(MONTH, DATEDIFF(MONTH, 0, @forwhichdate), 0)
) as bd, 1 as n
UNION ALL
SELECT DATEADD(DAY,
CASE
    (DATEPART(WEEKDAY, bd.bd) + @@DATEFIRST - 1) % 7
    WHEN 5 THEN 3
    WHEN 6 THEN 2
    ELSE 1
END,
bd.bd
) as db, 
bd.n+1
from bd where month(bd.bd) = month(@forwhichdate)
)
select * from bd

Result:

bd                      n
----------------------- -----------
2017-04-03 00:00:00.000 1
2017-04-04 00:00:00.000 2
2017-04-05 00:00:00.000 3
2017-04-06 00:00:00.000 4
2017-04-07 00:00:00.000 5
2017-04-10 00:00:00.000 6
2017-04-11 00:00:00.000 7
2017-04-12 00:00:00.000 8
2017-04-13 00:00:00.000 9
2017-04-14 00:00:00.000 10
2017-04-17 00:00:00.000 11
2017-04-18 00:00:00.000 12
2017-04-19 00:00:00.000 13
2017-04-20 00:00:00.000 14
2017-04-21 00:00:00.000 15
2017-04-24 00:00:00.000 16
2017-04-25 00:00:00.000 17
2017-04-26 00:00:00.000 18
2017-04-27 00:00:00.000 19
2017-04-28 00:00:00.000 20
2017-05-01 00:00:00.000 21

(21 row(s) affected)

However, in reality your query should also check for the holidays.

you can use this logic.. where will find the next business day skipping the weekends.

declare @datetoday date = '2017-04-01'


select iif(datepart(dw,@datetoday)=1, dateadd(day,1,@datetoday),iif(datepart(dw,@datetoday)=7,dateadd(day,2,@datetoday),@datetoday))

A calendar/tally table would do the trick, but we can use an ad-hod tally table.

Declare @Date1 date = '2017-03-01'
Declare @Date2 date = EOMonth(@Date1)

Select *
 From (
        Select Date    = D
              ,WeekDay = DateName(WEEKDAY,D)
              ,DayCode = concat('BD',Row_Number() over(Order By D))
         From (Select Top (DateDiff(DD,@Date1,@Date2)+1) D=DateAdd(DD,-1+Row_Number() Over (Order By Number),@Date1) From  master..spt_values) A
         Where DateName(WEEKDAY,D) Not in ('Saturday','Sunday')
        Union All
        Select Date    = D
              ,WeekDay = DateName(WEEKDAY,D)
              ,DayCode = concat('CD',Row_Number() over(Order By D))
         From (Select Top (DateDiff(DD,@Date1,@Date2)+1) D=DateAdd(DD,-1+Row_Number() Over (Order By Number),@Date1) From  master..spt_values) A
      ) A
 Where substring(DayCode,3,2)<=6

Returns

Date        WeekDay     DayCode
2017-03-01  Wednesday   BD1
2017-03-02  Thursday    BD2
2017-03-03  Friday      BD3
2017-03-06  Monday      BD4  --< Notice BD4 is Monday
2017-03-07  Tuesday     BD5
2017-03-08  Wednesday   BD6
2017-03-01  Wednesday   CD1
2017-03-02  Thursday    CD2
2017-03-03  Friday      CD3
2017-03-04  Saturday    CD4
2017-03-05  Sunday      CD5
2017-03-06  Monday      CD6

IMHO , your table structure is wrong in two way, i) daterule column should be split in 2 columns like in my CTE.Then calculation will be far easier.

ii) Secondly you don't keep your column in such pivoted manner.this it will keep on increasing.So hope your handling your requirement in correct way.

Keeping your current structure in mind,

declare @t table(daterule varchar(20),Marchexpected date , Aprilexpected date )
insert into @t VALUES
('BD1','3/1/2017', '4/3/2017')
,('BD2','3/2/2017',  null       )
,('BD3','3/3/2017',    null  )
,('BD4','3/4/2017',    null  )
,('BD5',  null      ,  null  )
,('BD6',  null      ,  null  )
,('CD1','3/1/2017',    null  )
,('CD2','3/2/2017',    null  )
,('CD3','3/3/2017',    null  )
,('CD4','3/4/2017',    null  )
,('CD5','3/5/2017',    null  )
,('CD6','3/6/2017',    null  )
declare @AprilDate date='2017-04-01'
;With CTE as
(
SELECT *
,case when daterule like 'BD%' then 'BD' else 'CD' end ruletype
,cast(replace(replace(daterule,'BD',  '' ),'CD','') as int) ruletypeid
 from @t
)
select daterule,Marchexpected
,case when datename(dw, dateadd(day,(ruletypeid-1),@AprilDate))='Saturday'
then dateadd(day,(ruletypeid+1),@AprilDate)
when datename(dw, dateadd(day,(ruletypeid-1),@AprilDate))='Sunday'
then dateadd(day,(ruletypeid),@AprilDate)
else
dateadd(day,(ruletypeid-1),@AprilDate)
END
Aprilexpected
from cte
where   ruletype='BD'

union ALL


select daterule,Marchexpected
,dateadd(day,(ruletypeid-1),@AprilDate)
from cte
where   ruletype='CD'
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!