我在SQL Server 2012中有一个表,每月手动更新一次,以反映预期进入的文件的日期。日期规则已有值但预期日期列是手动更新的。如果预期在BD1(营业日1),我将更新到该月的第一个非周末日。如果预期在CD1(日历第1天),我会更新到第一,无论它是在工作日还是周末等等。是否可以编写更新查询,它将循环遍历值并自动更新?我无法确定更新到正确的工作日。
date rule | March expected date | April expected date | -------------------------------------------------------- | BD1 | 3/1/2017 | 4/3/2017 | | BD2 | 3/2/2017 | | | BD3 | 3/3/2017 | | | BD4 | 3/6/2017 | | | BD5 | | | | BD6 | | | | CD1 | 3/1/2017 | | | CD2 | 3/2/2017 | | | CD3 | 3/3/2017 | | | CD4 | 3/4/2017 | | | CD5 | 3/5/2017 | | | CD6 | 3/6/2017 | |
我使用以下代码计算第一个工作日
SELECT DATEADD(DAY,
CASE
(DATEPART(WEEKDAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)) + @@DATEFIRST - 1) % 7
WHEN 6 THEN 2
WHEN 7 THEN 1
ELSE 0
END,
DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
)
但是当它到了营业日4时,它会给我3/4/2017这是一个星期六,而不是3/6/2017,这是下周一。我很难知道如何解决这个问题。我认为循环更新查询是最好的
答案 0 :(得分:1)
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
结果:
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)
但是,实际上您的查询还应该检查假期。
答案 1 :(得分:0)
你可以使用这个逻辑..在哪里可以找到跳过周末的下一个工作日。
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))
答案 2 :(得分:0)
日历/计数表可以解决问题,但我们可以使用ad-hod计数表。
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
返回
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
答案 3 :(得分:0)
恕我直言,你的桌面结构有两种错误, i)daterule列应该像我的CTE一样分为两列。然后计算将更加容易。
ii)其次,你不能以专业的方式保持你的专栏。这将继续增加。所以希望你以正确的方式处理你的要求。
牢记当前的结构,
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'