选择日期+3天,不包括周末和节假日

Posted

技术标签:

【中文标题】选择日期+3天,不包括周末和节假日【英文标题】:Select date + 3 days, not including weekends and holidays 【发布时间】:2013-05-28 18:59:43 【问题描述】:

我已经找到了许多关于在 SQL 中进行日期差异问题的答案,不包括周末和节假日。我的问题是我需要进行日期比较 - 有多少子记录的工作日期在父记录发送日期的三天内?

大多数日期差异答案都涉及日历表,我认为如果我可以构建一个返回 date+3 的子选择,我就可以解决剩下的问题。但我不知道如何返回日期+3。

所以:

CREATE TABLE calendar
(
    thedate DATETIME NOT NULL,
    isweekday SMALLINT NULL,
    isholiday SMALLINT NULL
);

还有:

SELECT thedate AS fromdate, xxx AS todate
FROM calendar

我想要的 todate 是 fromdate + 72 小时,不包括周末和节假日。在 isweekday 而不是 isholiday 的情况下执行 COUNT(*) 很简单,但执行 DATEADD() 是另一回事。

我不知道从哪里开始。

【问题讨论】:

等等...“我想如果我可以构建一个返回日期+3 的子选择,我就可以解决剩下的问题”——当然。完成所有工作后,您就可以解决剩下的问题了。 :) 您还没有将原始问题简化为更简单的问题,您尝试的简化同样复杂。 【参考方案1】:

编辑: 更改为将非工作日包含为有效的 fromDates。

WITH rankedDates AS
    (
        SELECT 
            thedate
            , ROW_NUMBER()
                OVER(
                    ORDER BY thedate
                    ) dateRank
        FROM 
            calendar c
        WHERE 
            c.isweekday = 1 
            AND 
            c.isholiday = 0
    )
SELECT 
    c1.fromdate
    , rd2.thedate todate
FROM
    ( 
        SELECT 
            c.thedate fromDate
            , 
                (
                    SELECT 
                        TOP 1 daterank
                    FROM 
                        rankedDates rd
                    WHERE
                        rd.thedate <= c.thedate
                    ORDER BY 
                        thedate DESC
                ) dateRank
        FROM 
            calendar c
    ) c1        
LEFT JOIN
    rankedDates rd2
    ON 
        c1.dateRank + 3 = rd2.dateRank        

您可以在日历表上放置一个日期排名列以简化此操作并避免 CTE:

CREATE TABLE
    calendar
    (
        TheDate DATETIME PRIMARY KEY
        , isweekday BIT NOT NULL
        , isHoliday BIT NOT NULL DEFAULT 0
        , dateRank INT NOT NULL
    );

然后您将仅在非节假日工作日设置 daterank 列。

【讨论】:

这几乎行得通。但是因为您是从rankedDates 中提取fromDate,所以它不会返回周末和节假日的值。 哦,所以假期和周末需要 'todate' 值,但需要将 'fromdate' 限制为非假期工作日? 是的。考虑一下,如果我将它添加到表中,而不是使用 CFE,我可以在设置 dateRank 列的脚本中执行此操作。【参考方案2】:

这应该可以解决问题,将“顶部”中的数字更改为您想要包含的天数。

declare @date as datetime

set @date = '5/23/13'

select
    max(_businessDates.thedate)
from (
    select 
         top 3 _Calendar.thedate 
    from calendar _Calendar
    where _Calendar.isWeekday = 1 
         and _Calendar.isholiday = 0
         and _Calendar.thedate >= @date
    order by 
         _Calendar.thedate
) as _businessDates

对于可以前进或后退一定天数的动态版本,请尝试以下操作:

declare @date as datetime
declare @DayOffset as int

set @date = '5/28/13'
set @DayOffset = -3

select
    (case when @DayOffset >= 0 then 
            max(_businessDates.thedate) 
        else 
            min(_businessDates.thedate) 
        end)
from (
    select 
         top (abs(@DayOffset) + (case when @DayOffset >= 0 then 1 else 0 end)) _Calendar.thedate
    from calendar _Calendar
    where _Calendar.isWeekday = 1
        and _Calendar.isholiday = 0
        and ( (@DayOffset >= 0 and _Calendar.thedate >= @date)
        or  (@DayOffset < 0 and _Calendar.thedate < @date) )
    order by 
         cast(_Calendar.thedate as int) * (case when @DayOffset >=0 then 1 else -1 end)
) as _businessDates

您可以将@DayOffset 设置为正数或负数。

【讨论】:

这是一个独立的查询。但我需要将其用作连接到另一个表的子选择,其中@date 是另一个表中的一个字段。我不能,AIUI,在子选择的上下文中使用字段引用。 我将其创建为我在选择列表中调用的函数。 select *, (select [dbo].[FunctionName]('myTable.thedate',3)) as offsetDate from myTable 添加了一个可以使用 dateadd 加入查询的新答案。【参考方案3】:

你只需要 DATEADD,除非我不理解你的问题。

DATEADD(DAY,3,fromdate)

编辑:我知道,不包括周末或节假日,将立即更新。

更新:看起来 Jason 搞定了,但如果您使用 SQL2012 的机会不大,这里是简单版本:

SELECT todate = thedate
       fromdate = LEAD(thedate,3) OVER (ORDER BY thedate)
FROM calendar
WHERE isweekday = 1
 AND isHoliday = 0

【讨论】:

是的,我也是这么想的,这个问题的措辞有点混乱。 :) 我想增加三天,不包括节假日和周末。也就是说,thedate + 需要多少天才能获得 isholiday 为 0 且 isweekday 为 1 的三天。【参考方案4】:

如果您需要它作为 dateAdd 查询,请尝试此操作:

SELECT 
     allDates.thedate fromDate
    ,min(nonWeekendHoliday.thedate) toDate
FROM (    
    SELECT 
        thedate
    FROM 
       calendar _calendar
) allDates
LEFT JOIN (
    SELECT 
        thedate
    FROM 
       calendar _calendar
    WHERE 
        _calendar.isweekday = 1 
        AND 
        _calendar.isholiday = 0 
) nonWeekendHoliday
    on dateadd(d,3,allDates.thedate) <= nonWeekendHoliday.thedate
where allDates.thedate between '5/20/13' and '5/31/13'
group by
     allDates.thedate

【讨论】:

以上是关于选择日期+3天,不包括周末和节假日的主要内容,如果未能解决你的问题,请参考以下文章

日期选择器国定假日计数

用java 进行日期计算,获取当前天+1天,周末节假日不算,在线等待中,十万火急……

从日期中添加或减去天数时如何避免周末或节假日[重复]

在日期时间选择器AngularJs中的特定日期显示颜色

jquery ui 多日期选择器数据范围没有周末

从日期计算中排除周末和自定义日期(即假期)