0

我有一个棘手的问题,我在精神层面上正在努力解决。

在我们的数据库中,我们有一个显示未来几年英国假期的表格,一个存储的函数将一个记录集返回到我的前端。

我的记录集中有一个名为“可删除”的标志,它允许前端决定是否可以在数据网格中显示上下文菜单,从而允许删除该记录。

目前,测试(在我的存储过程中)只检查日期列是否具有三天前或更早的日期。

case when DATEDIFF(d,a.[date],GETDATE()) > 3 then 1 else 0 end as [deletable]

如何通过检查周末和假期表的“假期”列(这是一个日期时间)来修改它以查找上一个工作日期,并查看我的记录集行中的 [日期] 列是否是 3 个工作日前,考虑到假期从假期表和周末?

所以如果 [date] 列是 5 月 23 日,而今天的日期是 5 月 28 日,那么该列返回 0,因为 27 日是银行假日,而第二天它会返回 1,因为会有超过 3 个工作日的差异.

有没有一种优雅的方法来做到这一点?

谢谢菲利普

4

3 回答 3

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

于 2013-06-07T13:51:34.140 回答
1

您应该从 DATEDIFF 中减去 a.[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]

拉兹万

于 2013-06-07T13:42:59.437 回答
1

我假设您没有日历表,尽管我强烈建议您创建一个,但您仍然可以在没有日历表的情况下实现此目的:

以下将为您提供从昨天开始向后追溯的 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;

注意您应该明确设置您的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;
于 2013-06-07T14:39:22.543 回答