我有一个棘手的问题,我在精神层面上苦苦挣扎。
在我们的数据库中,我们有一个表格显示未来几年的英国假期,而存储的函数会将记录集返回给我的前端。
我的记录集中有一个名为'deletable'的标志,它允许前端决定是否可以在数据网格中显示上下文菜单,从而允许删除该记录。
目前,测试(在我的存储过程中)仅检查日期列是否具有三天或更早的日期。
case when DATEDIFF(d,a.[date],GETDATE()) > 3 then 1 else 0 end as [deletable]
如何通过检查周末和Holidays表'Holiday'列(这是一个Datetime)来修改它以查找上一个工作日期,并查看我的记录集行中的[date]列是否在3个工作日之前,考虑到假期表和周末的假期?
所以如果[date]列是5月23日,今天的日期是5月28日,那么该列返回0,因为27日是银行假日,而第二天它将返回1,因为会有3个以上工作日差异。
有没有一种优雅的方法可以做到这一点?
感谢 菲利普
答案 0 :(得分:2)
好的,我完全重构了这个。
declare
@DeletablePeriodStart datetime,
@BusinessDays int
set @DeletablePeriodStart = dateadd(d,0,datediff(d,0,getdate()))
set @BusinessDays = 0
while @BusinessDays < 3
begin
set @DeletablePeriodStart = dateadd(d,-1,@DeletablePeriodStart)
if datepart(dw,@DeletablePeriodStart) not in (1,7) and
not exists (select * from HolidayTable where Holiday = @DeletablePeriodStart)
begin
set @BusinessDays = @BusinessDays + 1
end
end
这一次它没有做出任何假设。它运行一个快速循环检查每天是否是一个有效的工作日,并且直到它计算其中三个为止。然后稍后检查a.[date] >= @DeletablePeriodStart
答案 1 :(得分:1)
您应该从DATEDIFF中减去。[date]和GETDATE()之间的假期数。尝试这样的事情:
case when DATEDIFF(d,a.[date],GETDATE())-(
SELECT COUNT(*) FROM Holidays
WHERE HolidayDate BETWEEN a.[date] AND GETDATE()
)>3 then 1 else 0 end as [deletable]
勒兹
答案 2 :(得分:1)
我假设您没有Calendar table,虽然我强烈建议您创建一个,但如果没有一个,您仍然可以实现这一目标:
以下内容将为您提供昨天倒退的2047个日期列表(使用系统表Master..spt_values
):
WITH Dates AS
( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE))
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
)
SELECT Dates.Date
FROM Dates
ORDER BY Dates.Date DESC;
然后,您需要使用以下内容从表中排除周末和假期:
SET DATEFIRST 1;
WITH Dates AS
( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE))
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
)
SELECT Dates.Date
FROM Dates
WHERE DATEPART(WEEKDAY, Dates.Date) <= 5
AND NOT EXISTS
( SELECT 1
FROM HolidayTable h
WHERE Dates.Date = h.HolidayDate
)
ORDER BY Dates.Date DESC;
N.B。您应该明确设置DATEFIRST
而不是依赖服务器默认值
上面给出了今天之前的工作日列表,然后您可以使用ROW_NUMBER()
函数,在列表中获得第3次出现,给出最终查询:
WITH Dates AS
( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE))
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
), WorkingDays AS
( SELECT Dates.Date, RN = ROW_NUMBER() OVER(ORDER BY Dates.Date DESC)
FROM Dates
WHERE DATEPART(WEEKDAY, Dates.Date) <= 5
AND NOT EXISTS
( SELECT 1
FROM HolidayTable h
WHERE Dates.Date = h.HolidayDate
)
)
SELECT WorkingDays.Date
FROM WorkingDays
WHERE RN = 3;
或者如果您愿意,可以使用一个查询(完全相同的原理)来完成:
SELECT d.Date
FROM ( SELECT Date = DATEADD(DAY, -number, CAST(GETDATE() AS DATE)), RN = ROW_NUMBER() OVER(ORDER BY number)
FROM Master..spt_values
WHERE type = 'P'
AND number > 0
AND DATEPART(WEEKDAY, DATEADD(DAY, -number, CAST(GETDATE() AS DATE))) <= 5
AND NOT EXISTS
( SELECT 1
FROM HolidayTable h
WHERE DATEADD(DAY, -number, CAST(GETDATE() AS DATE)) = h.HolidayDate
)
) d
WHERE rn = 3;