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

时间:2013-05-28 18:59:43

标签: sql sql-server

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

大多数日期差异答案都涉及一个日历表,我想如果我可以构建一个返回日期+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从72小时开始,不包括周末和假日。做一个COUNT(*),其中isweekday而不是isholiday很简单,但做一个DATEADD()是另一回事。

我不知道从哪里开始。

4 个答案:

答案 0 :(得分:1)

修改 已更改为将非工作日包含为有效日期。

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列设置为非假日工作日。

答案 1 :(得分:1)

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

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设置为正数或负数。

答案 2 :(得分:0)

你只需要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

答案 3 :(得分:0)

如果您需要使用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