복붙노트

[SQL] 루프없이 SQL 날짜에 영업일 추가

SQL

루프없이 SQL 날짜에 영업일 추가

나는 현재, 예를 들어, 날짜에 일의 일정 금액을 추가 내 SQL 데이터베이스의 기능을 가지고 당신이 목요일의 날짜를 입력하고 이일을 추가 할 경우, 다음 월요일의 날짜를 반환합니다. 내가 어떤 휴일에 대한 방해 아니에요, 단지 주말은 제외됩니다.

이 문제는 현재 while 루프를 사용하여 수행되고, 그 용적이 사용하는 테이블을 생성 할 때 그 프로 시저를 느리게 할 표시이다. 루프 또는 커서 동안하지 않고이 계산을 수행 할 수있는 방법이 있는지 아는 사람 있나요?

그냥 내용이 현재의 기능은 다음과 같습니다

ALTER FUNCTION [dbo].[AddWorkDaysToDate]
(   
@fromDate       datetime,
@daysToAdd      int
)
RETURNS datetime
AS
BEGIN   
DECLARE @toDate datetime
DECLARE @daysAdded integer

-- add the days, ignoring weekends (i.e. add working days)
set @daysAdded = 1
set @toDate = @fromDate

while @daysAdded <= @daysToAdd
begin
    -- add a day to the to date
    set @toDate = DateAdd(day, 1, @toDate)
    -- only move on a day if we've hit a week day
    if (DatePart(dw, @toDate) != 1) and (DatePart(dw, @toDate) != 7)
    begin
        set @daysAdded = @daysAdded + 1
    end
end

RETURN @toDate

END

해결법

  1. ==============================

    1.이 승인 된 이후 원본이 잘못 때문에 대답은 크게 변경되었습니다. 그래도 새 쿼리에 더 확신, 그리고 DATEFIRST에 의존하지 않는

    이 승인 된 이후 원본이 잘못 때문에 대답은 크게 변경되었습니다. 그래도 새 쿼리에 더 확신, 그리고 DATEFIRST에 의존하지 않는

    나는이 그것을 커버해야한다고 생각 :

    declare @fromDate datetime
    declare @daysToAdd int
    
    select @fromDate = '20130123',@DaysToAdd = 4
    
    declare @Saturday int
    select @Saturday = DATEPART(weekday,'20130126')
    
    ;with Numbers as (
        select 0 as n union all select 1 union all select 2 union all select 3 union all select 4
    ), Split as (
        select @DaysToAdd%5 as PartialDays,@DaysToAdd/5 as WeeksToAdd
    ), WeekendCheck as (
        select WeeksToAdd,PartialDays,MAX(CASE WHEN DATEPART(weekday,DATEADD(day,n.n,@fromDate))=@Saturday THEN 1 ELSE 0 END) as HitWeekend
        from
        Split t
            left join
        Numbers n
            on
                t.PartialDays >= n.n
    group by WeeksToAdd,PartialDays
    )
    select DATEADD(day,WeeksToAdd*7+PartialDays+CASE WHEN HitWeekend=1 THEN 2 ELSE 0 END,@fromDate)
    from WeekendCheck
    

    우리는 시간이 몇 주 주일 이내 일 수에 추가 될 분할합니다. 그 며칠 추가하는 것은 우리가 토요일 타격 발생합니다 경우 우리는 다음 해결하기 위해 적은 수의 테이블을 사용합니다. 만약 그렇다면, 우리는 전체에 2 일 이상을 추가해야합니다.

  2. ==============================

    2.사람이 TSQL 솔루션을 찾고있는 경우에 더 낫다. 어떤 루프도없고, 테이블, 네거티브와 어떠한 경우에도 문 및 작동합니다. 사람이 이길 것을 할 수 있습니까?

    사람이 TSQL 솔루션을 찾고있는 경우에 더 낫다. 어떤 루프도없고, 테이블, 네거티브와 어떠한 경우에도 문 및 작동합니다. 사람이 이길 것을 할 수 있습니까?

    CREATE FUNCTION[dbo].[AddBusinessDays](@Date date,@n INT)
    RETURNS DATE AS 
    BEGIN
    DECLARE @d INT;SET @d=4-SIGN(@n)*(4-DATEPART(DW,@Date));
    RETURN DATEADD(D,@n+((ABS(@n)+@d-2)/5)*2*SIGN(@n)-@d/7,@Date);
    END
    
  3. ==============================

    3.이 질문에 허용 된 대답의 오프 구축, 다음과 같은 사용자 정의 함수 (UDF)는 모든 경우에 작동한다 -에 관계없이 @@ DATEFIRST에 대한 설정.

    이 질문에 허용 된 대답의 오프 구축, 다음과 같은 사용자 정의 함수 (UDF)는 모든 경우에 작동한다 -에 관계없이 @@ DATEFIRST에 대한 설정.

    UPDATE는 : 코멘트를 아래에 나타냅니다 것처럼 FROMDATE 평일 될 경우,이 기능이 설계되어 있습니다. 주말 하루가 FROMDATE로 전달 될 때의 동작은 정의되고 있지 않습니다.

    ALTER FUNCTION [dbo].[BusinessDaysDateAdd] 
    (
       @FromDate datetime,
       @DaysToAdd int
    )
    RETURNS datetime
    AS
    BEGIN
       DECLARE @Result datetime
    
       SET @Result = DATEADD(day, (@DaysToAdd % 5) + CASE ((@@DATEFIRST + DATEPART(weekday, @FromDate) + (@DaysToAdd % 5)) % 7)
                                                     WHEN 0 THEN 2
                                                     WHEN 1 THEN 1
                                                     ELSE 0 END, DATEADD(week, (@DaysToAdd / 5), @FromDate))
    
       RETURN @Result
    END
    
  4. ==============================

    4.이 답변은 ElmerMiller의 대답 @에 근거한다.

    이 답변은 ElmerMiller의 대답 @에 근거한다.

    그것은 @FistOfFury에서 일요일 코멘트에 부정적인 값을 수정

    그리고 DATEFIRST는 @Damien_The_Unbeliever에서 코멘트 설정

    이제 보정 기능

    CREATE FUNCTION[dbo].[AddBusinessDays](@Date DATE,@n INT)
    RETURNS DATE AS 
    BEGIN
    DECLARE @d INT,@f INT,@DW INT;
    SET @f=CAST(abs(1^SIGN(DATEPART(DW, @Date)-(7-@@DATEFIRST))) AS BIT)
    SET @DW=DATEPART(DW,@Date)-(7-@@DATEFIRST)*(@f^1)+@@DATEFIRST*(@f&1)
    SET @d=4-SIGN(@n)*(4-@DW);
    RETURN DATEADD(D,@n+((ABS(@n)+(@d%(8+SIGN(@n)))-2)/5)*2*SIGN(@n)-@d/7,@Date);
    END
    
  5. ==============================

    5.당신에 대해 생각 미리 채우는 예를 들어 WorkingDays (INT의 DaySequenceId, 날짜 WorkingDate)에 대해, (함수를 사용) 일을 모두 포함하는 룩업 테이블은, 당신은 다음 @fromDate의 DaySequenceId을 선택하여이 테이블을 사용할 수 있습니다 새로운 작업 날짜를 얻을 수 @daysToAdd를 추가합니다. 물론이 방법은 또한 WorkingDays 테이블을 관리의 추가 오버 헤드를 가지고 있지만, 당신은 당신이 기대하는 날짜의 범위를 미리 채울 수 있습니다. 다른 단점은 단지 WorkingDays 테이블에 포함 된 것이어야합니다 계산 될 수있는 작업 날짜입니다.

    당신에 대해 생각 미리 채우는 예를 들어 WorkingDays (INT의 DaySequenceId, 날짜 WorkingDate)에 대해, (함수를 사용) 일을 모두 포함하는 룩업 테이블은, 당신은 다음 @fromDate의 DaySequenceId을 선택하여이 테이블을 사용할 수 있습니다 새로운 작업 날짜를 얻을 수 @daysToAdd를 추가합니다. 물론이 방법은 또한 WorkingDays 테이블을 관리의 추가 오버 헤드를 가지고 있지만, 당신은 당신이 기대하는 날짜의 범위를 미리 채울 수 있습니다. 다른 단점은 단지 WorkingDays 테이블에 포함 된 것이어야합니다 계산 될 수있는 작업 날짜입니다.

  6. ==============================

    6.* 나는 전에 그것을 수정이있어하는 동안이 오래된 스레드하지만 발견 뭔가 매우 유용한 알고있다.

    * 나는 전에 그것을 수정이있어하는 동안이 오래된 스레드하지만 발견 뭔가 매우 유용한 알고있다.

    select ((DATEADD(d,DATEDIFF(d,0,(DATEADD (d,2,@fromDate))),@numbOfDays)))*
    

    업데이트 : 나는 (하나의 문에서) 코드 조각을 발견하고 기능을 사용하지 않도록하기 위해 서둘러 미안 해요, 내가 여기에 잘못된 코드를 기록했다.

    비트는 위에서 언급 한 추가하는 일수가 7 이하인 경우에 사용할 수 있습니다.

    나는 더 나은 이해에 필요한 매개 변수를 사용하여 코드를 변경했습니다.

    어쨌든, 나는 '네이트 쿡'위에서 언급 한 것을 사용하여 끝났다. 그리고 단 한 줄의 코드로 사용했다. (I 함수를 사용 억제하고 있기 때문에)

    네이트 코드

    select(
    DATEADD(day, (@days % 5) + 
    CASE ((@@DATEFIRST + DATEPART(weekday, GETDATE()) + (@days % 5)) % 7)
    WHEN 0 THEN 2
    WHEN 1 THEN 1
    ELSE 0 END, DATEADD(week, (@days / 5), GETDATE()))
    )
    
  7. ==============================

    7.아민의 의견이에 한 줄의 솔루션입니다, 위의 네이트 요리사의 대답에 확장하려면 :

    아민의 의견이에 한 줄의 솔루션입니다, 위의 네이트 요리사의 대답에 확장하려면 :

    declare @DaysToAdd int , @FromDate datetime 
    set @DaysToAdd=-5      --5 days prior is 3/28/14
    set @FromDate='4/4/14'
    select 
        DATEADD(day, (@DaysToAdd % 5) 
        +   CASE 
            WHEN ((@@DATEFIRST + DATEPART(weekday, @FromDate)) % 7 + (@DaysToAdd % 5)) > 6 THEN 2 
            ELSE 0 
            END
        , DATEADD(week, (@DaysToAdd / 5), @FromDate))
    

    추가하거나 각각의 시간에 앞뒤로 이동하는 일 뺄 수 있습니다.

  8. ==============================

    8.

    CREATE FUNCTION DateAddBusinessDays
    (
        @Days int,
        @Date datetime  
    )
    RETURNS datetime
    AS
    BEGIN
        DECLARE @DayOfWeek int;
    
        SET @DayOfWeek = CASE 
                            WHEN @Days < 0 THEN (@@DateFirst + DATEPART(weekday, @Date) - 20) % 7
                            ELSE (@@DateFirst + DATEPART(weekday, @Date) - 2) % 7
                         END;
    
        IF @DayOfWeek = 6 SET @Days = @Days - 1
        ELSE IF @DayOfWeek = -6 SET @Days = @Days + 1;
    
        RETURN @Date + @Days + (@Days + @DayOfWeek) / 5 * 2;
    END;
    

    이 기능은 추가와 관계없이 @@ DATEFIRST 값의 일을 뺄 수 있습니다. 일이 일의 음의 번호를 사용 빼려면.

  9. ==============================

    9.나는 시험에 순간에는 SQL 서버가없는 그러나 이것은 생각이다 :

    나는 시험에 순간에는 SQL 서버가없는 그러나 이것은 생각이다 :

    ALTER FUNCTION [dbo].[AddWorkDaysToDate]
    (   
    @fromDate       datetime,
    @daysToAdd      int
    )
    RETURNS datetime
    AS
    BEGIN   
    DECLARE @dw integer
    DECLARE @toDate datetime
    
    set datefirst 1
    set @toDate = dateadd(day, @daysToAdd, @fromDate)
    set @dw = datepart(dw, @toDate)
    
    if @dw > 5 set @toDate = dateadd(day, 8 - @dw, @toDate)
    
    RETURN @toDate
    
    END
    
  10. ==============================

    10.코드 주셔서 감사합니다 데미안. 거기는 일요일에만 일일를 추가한다는 점에서 약간의 오류가 CALCS에, 그리고 영업일 수가 주말을 넘어 (그러나 주말에 착륙하지 않았다) 할 때 여분의 이일은 고려되지 않았 음. 여기 7. 희망이 도움이에서 DATEFIRST 기본 작동 Damiens 코드의 수정 된 버전입니다.

    코드 주셔서 감사합니다 데미안. 거기는 일요일에만 일일를 추가한다는 점에서 약간의 오류가 CALCS에, 그리고 영업일 수가 주말을 넘어 (그러나 주말에 착륙하지 않았다) 할 때 여분의 이일은 고려되지 않았 음. 여기 7. 희망이 도움이에서 DATEFIRST 기본 작동 Damiens 코드의 수정 된 버전입니다.

    CREATE FUNCTION [dbo].[fn_AddBusinessDays]  
    (  
        @StartDate datetime,  
        @BusinessDays int  
    ) 
    RETURNS datetime  
    AS  
    BEGIN 
    DECLARE @EndDate datetime
    
    SET @EndDate = DATEADD(day, @BusinessDays%5 + 
               CASE         
            WHEN DATEPART(weekday,@StartDate) +  @BusinessDays%5 > 6 THEN 2                  
            ELSE 0 
               END,     
       DATEADD(week,@BusinessDays/5,@StartDate))    
    
       RETURN @EndDate
    END  
    GO
    
  11. ==============================

    11.질문의 허용 대답은 잘못된 결과를 얻을 수 있습니다. 예를 들면 선택 @fromDate = '03 -11-1983 '1983년 3월 14일에 @DaysToAdd = 3 개 1983년 3월 16일 결과가 기대된다.

    질문의 허용 대답은 잘못된 결과를 얻을 수 있습니다. 예를 들면 선택 @fromDate = '03 -11-1983 '1983년 3월 14일에 @DaysToAdd = 3 개 1983년 3월 16일 결과가 기대된다.

    여기 작업 솔루션을 게시하지만 완전성을 위해 나 또한 여기에 추가합니다. 당신이 두 가지 방법의 세부 사항에 관심이 있다면 내 원래의 대답을 방문하여 이동합니다. 그렇지 않은 경우, 단순히 SQL 프로젝트 및 사용 UTL_DateAddWorkingDays에 / 파스타이 복사

    DATEFIRST 7의 기본값으로 설정되어있는 경우 내 솔루션에만 작동합니다.

    테스트 스크립트는 다양한 방법을 테스트하는 데 사용

    CREATE FUNCTION [dbo].[UTL_DateAddWorkingDays]
    (   
        @date datetime,
        @days int
    )
    RETURNS TABLE AS RETURN 
    (
        SELECT 
            CASE 
                WHEN @days = 0 THEN @date
                WHEN DATEPART(dw, @date) = 1 THEN (SELECT Date FROM [dbo].[UTL_DateAddWorkingDays_Inner](DATEADD(d, 1, @date), @days - 1))
                WHEN DATEPART(dw, @date) = 7 THEN (SELECT Date FROM [dbo].[UTL_DateAddWorkingDays_Inner](DATEADD(d, 2, @date), @days - 1))
                ELSE (SELECT Date FROM [dbo].[UTL_DateAddWorkingDays_Inner](@date, @days))
            END AS Date
    )
    
    CREATE FUNCTION [dbo].[UTL_DateAddWorkingDays_Inner]
    (   
        @date datetime,
        @days int
    )
    RETURNS TABLE AS RETURN 
    (
        SELECT 
            DATEADD(d
            , (@days / 5) * 7 
              + (@days % 5) 
              + (CASE WHEN ((@days%5) + DATEPART(dw, @date)) IN (1,7,8,9,10) THEN 2 ELSE 0 END)
            , @date) AS Date
    )
    
  12. ==============================

    12.이것은 내가 무엇을 사용 :

    이것은 내가 무엇을 사용 :

    SET DATEFIRST 1;
    
    SELECT DATEADD(dw, (**NumberToAdd**/5)*7+(**NumberToAdd** % 5) + 
    (CASE WHEN DATEPART(dw,**YourDate**) + (**NumberToAdd** % 5) > 5 
    THEN 2 ELSE 0 END), **YourDate**) AS IncrementedDate
    FROM YourTable t
    

    은 "SET DATEFIRST 1;" 일부는 일주일의 첫날 월요일을 설정하는 것이 필요하다.

  13. ==============================

    13.나는 모든 솔루션이 여기에 제시하지 않고 그 일의 아무도 테스트했습니다. 다음은 위의 방법을 많이 부러 몇 가지 테스트 시나리오입니다. (토, 일 가정은 제외하는 일입니다) :

    나는 모든 솔루션이 여기에 제시하지 않고 그 일의 아무도 테스트했습니다. 다음은 위의 방법을 많이 부러 몇 가지 테스트 시나리오입니다. (토, 일 가정은 제외하는 일입니다) :

    토요일에 - 추가 0일 - 예상 결과 = 토요일

    일요일에 - 추가 0일 - 예상 결과 = 일요일

    금요일 - 추가 일일 - 예상 결과 = 다음 월요일

    토요일 - 추가 일일 - 예상 결과 = 다음 월요일

    일요일 - 추가 일일 - 예상 결과 = 다음 월요일

    금요일 - 추가 삼일 - 예상 결과 = 다음 수요일

    토요일 - 추가 오일 - 예상 결과 = 다음 금요일

    금요일 - 추가 오일 - 예상 결과 = 다음 금요일

    월요일부터 -Subtract 일일 - 예상 결과 = 이전 금요일

    일요일부터 -Subtract 일일 - 예상 결과 = 이전 금요일

    토요일에서 -Subtract 일일 - 예상 결과 = 이전 금요일

    = 이전 수요일 예상 결과 - 월요일부터 -Subtract 삼일

    = 이전 월요일 예상 결과 - 토요일에서 -Subtract 오일

    = 이전 월요일 예상 결과 - 월요일부터 -Subtract 오일

    여기에 내가이 전체 스레드를 읽고 논리의 좋은 조각을 따기 후 쓴 것입니다 :

    CREATE FUNCTION [dbo].[BusinessDateAdd]
    (
        @FromDate DATE
        ,@DaysToAdd INT
    )
    RETURNS DATE 
    AS 
    BEGIN
    
        --If there are no days to add or subtract, return the day that was passed in
        IF @DaysToAdd = 0 RETURN @FromDate
    
        DECLARE @Weeks INT
        DECLARE @DMod INT
        DECLARE @FromDateIndex INT
    
        --number of weeks
        SET @Weeks = @DaysToAdd/5
    
        --remainder of days
        SET @dmod = @DaysToAdd%5
    
        --Get the FromDate day of the week, this logic standardizes the @@DateFirst to Sunday = 1
        SET @FromDateIndex = (DATEPART(weekday, @FromDate) + @@DATEFIRST - 1) % 7 + 1
    
        /*Splitting the addition vs subtraction logic for readability*/
    
        --Adding business days
        IF @DaysToAdd > 0 
            BEGIN 
    
                --If the FromDate is on a weekend, move it to the previous Friday
                IF @FromDateIndex IN(1,7) 
                    BEGIN
                        SET @FromDate = DATEADD(dd,CASE @FromDateIndex WHEN 1 THEN -2 WHEN 7 THEN -1 END,@FromDate)
                        SET @FromDateIndex = 6
                    END
    
                SET @FromDate = DATEADD(dd, 
                    CASE 
                        --If the mod goes through the weekend, add 2 days to account for it
                        WHEN 
                            ((@FromDateIndex = 3 --Tuesday
                            AND @dmod > 3) --Days until Friday
                            OR
                            (@FromDateIndex = 4  --Wednesday
                            AND @dmod > 2)--Days until Friday
                            OR 
                            (@FromDateIndex = 5 --Thursday
                            AND @dmod > 1)--Days until Friday
                            OR 
                            (@FromDateIndex = 6 --Friday
                            AND @dmod > 0))--Days until Friday
                            THEN 
                                @DMod+2 
                        --Otherwise just add the mod
                        ELSE 
                            @DMod 
                    END, @FromDate)
    
            END
    
        --Subtracting business days
        IF @DaysToAdd < 0 
            BEGIN 
    
                --If the FromDate is on a weekend, move it to the next Monday
                IF @FromDateIndex IN(1,7) 
                    BEGIN
                        SET @FromDate = DATEADD(dd,CASE @FromDateIndex WHEN 1 THEN 1 WHEN 7 THEN 2 END,@FromDate)
                        SET @FromDateIndex = 2
                    END
    
                SET @FromDate = DATEADD(dd, 
                    CASE 
                        --If the mod goes through the weekend, subtract 2 days to account for it
                        WHEN 
                            ((@FromDateIndex = 5 --Thursday
                            AND @dmod < -3) --Days until Monday
                            OR
                            (@FromDateIndex = 4  --Wednesday
                            AND @dmod < -2)--Days until Monday
                            OR 
                            (@FromDateIndex = 3 --Tuesday
                            AND @dmod < -1)--Days until Monday
                            OR 
                            (@FromDateIndex = 2 --Monday
                            AND @dmod < 0))--Days until Monday
                            THEN 
                                @DMod-2 
                        --Otherwise just subtract the mod
                        ELSE 
                            @DMod 
                    END, @FromDate)
    
            END
    
        --Shift the date by the number of weeks
        SET @FromDate = DATEADD(ww,@Weeks,@FromDate)
    
        RETURN @FromDate
    
    END
    
  14. ==============================

    14.

    WITH get_dates
    AS
    (
        SELECT getdate() AS date, 0 as DayNo 
        UNION ALL
        SELECT date + 1 AS date, case when DATEPART(DW, date + 1) IN (1,7) then DayNo else DayNo + 1 end
        FROM get_dates
        WHERE DayNo < 4
    )
    SELECT max(date) FROM get_dates
    OPTION (MAXRECURSION 0) 
    
  15. ==============================

    15.이 오래된 스레드하지만 난 그냥 이런 짓을 한 후 모든 날짜와 테이블을 생성 :

    이 오래된 스레드하지만 난 그냥 이런 짓을 한 후 모든 날짜와 테이블을 생성 :

    SELECT Count(*) 
    FROM Date_Table
    WHERE [day] BETWEEN @StartDate and @EndDate
        AND DATENAME(weekday, [day]) NOT IN ('Sunday', 'Saturday')
    
  16. ==============================

    16.나는 늦게 조금이 문제에 따라 아마 다른 사람 비틀 거림 알고있다. 나는 그들의 대부분 계산 휴일 수 없습니다, 위의 솔루션을 시도했지만했습니다.

    나는 늦게 조금이 문제에 따라 아마 다른 사람 비틀 거림 알고있다. 나는 그들의 대부분 계산 휴일 수 없습니다, 위의 솔루션을 시도했지만했습니다.

    이것은 내가 시도하는 방법이다

    CREATE function [dbo].[DateAddWorkDay]
    (@days int,@FromDate Date)
    returns Date
    as
    begin
    declare @result date
    set @result = (
    select b
    from
    (
        SELECT
        b,
           (DATEDIFF(dd, a, b))
          -(DATEDIFF(wk, a, b) * 2)
          -(CASE WHEN DATENAME(dw, a) = 'Sunday' THEN 1 ELSE 0 END)
          -(CASE WHEN DATENAME(dw, b) = 'Saturday' THEN 1 ELSE 0 END)
          -COUNT(o.Holiday_Date) 
          as workday
        from
        (
        select 
        @FromDate as a,
        dateadd(DAY,num +@days,@FromDate) as b
        from (select row_number() over (order by (select NULL)) as num
              from Information_Schema.columns
             ) t
        where num <= 100 
        ) dt
        left join Holiday o on o.Holiday_Date between a and b and DATENAME(dw, o.Holiday_Date) not in('Saturday','Sunday') 
        where DATENAME(dw, b) not in('Saturday','Sunday')
              and b not in (select Holiday_Date from OP_Holiday where Holiday_Date between a and b) 
    
        group by a,b
    ) du
    where workday =@days 
    
    
    )
    return @result 
    end
    

    휴일 HOLIDAY_DATE있는 테이블은 휴가를위한 참고 자료로 인 경우

    이것은 어떤 사람을 도울 수 있기를 바랍니다.

  17. ==============================

    17.이 SQL 기능은 엑셀 WORKDAY 함수와 유사한 작동합니다. 그것은 당신을 도울 수 있기를 바랍니다.

    이 SQL 기능은 엑셀 WORKDAY 함수와 유사한 작동합니다. 그것은 당신을 도울 수 있기를 바랍니다.

    CREATE FUNCTION [dbo].[BusDaysDateAdd] 
    (
       @FromDate date,
       @DaysToAdd int
    )
    RETURNS date
    AS
    BEGIN
       DECLARE @Result date
       DECLARE @TempDate date
       DECLARE @Remainder int
       DECLARE @datePartValue int
    
       SET @TempDate = (DATEADD(week, (@DaysToAdd / 5), @FromDate))
       SET @Remainder = (@DaysToAdd % 5)
       SET @datePartValue = DATEPART(weekday, @TempDate)
       SET @Result = DATEADD(day,@Remainder + CASE WHEN @Remainder > 0 AND @datePartValue = 7 THEN 1
                                                    WHEN @Remainder >= 1 AND @datePartValue = 6 THEN 2
                                                    WHEN @Remainder >= 2 AND @datePartValue = 5 THEN 2
                                                    WHEN @Remainder >= 3 AND @datePartValue = 4 THEN 2
                                                    WHEN @Remainder >= 4 AND @datePartValue = 3 THEN 2
                                                    WHEN @Remainder >= 5 AND @datePartValue = 2 THEN 2
                                                    ELSE 0 END, @TempDate)
       RETURN @Result
    END
    GO
    

    참고

  18. ==============================

    18.나는 조금 늦게 파티에 있어요하지만 난 때문에 다른 솔루션의 단점이 내 자신의 버전을 작성 감아. 특히이 버전 주소는 거꾸로 계산하고, 주말에 시작.

    나는 조금 늦게 파티에 있어요하지만 난 때문에 다른 솔루션의 단점이 내 자신의 버전을 작성 감아. 특히이 버전 주소는 거꾸로 계산하고, 주말에 시작.

    당신이 주말 날짜 제로 일을 추가 할 경우, 발생할 수있는 모호한 상황이있다. 나는 날짜를 동일하게 유지했지만, 당신은 항상 반환 할 평일을 강제하려는 경우 당신은이 검사를 생략 할 수 있습니다.

    CREATE FUNCTION [dbo].[fn_AddBusinessDays]
    (
        @date datetime,
        @businessDays int
    )
    RETURNS datetime
    AS
    BEGIN
        --adjust for weeks first
        declare @weeksToAdd int = @businessDays / 7
        declare @daysToAdd int = @businessDays % 7
    
        --if subtracting days, subtract a week then offset
        if @businessDays < 0 begin
            set @daysToAdd = @businessDays + 5
            set @weeksToAdd = @weeksToAdd - 1
        end
    
        --saturday becomes zero using the modulo operator
        declare @originalDayOfWeek int = datepart(dw, @date) % 7
        declare @newDayOfWeek int = datepart(dw, dateadd(d, @daysToAdd, @date)) % 7
    
        --special case for when beginning date is weekend
        --adding zero on a weekend keeps the same date. you can remove the <> 0 check if you want Sunday + 0 => Monday
        declare @dateOffset int = case
            when @businessDays <> 0 and @originalDayOfWeek = 0 then 2
            when @businessDays <> 0 and @originalDayOfWeek = 1 then 1
            when @businessDays <> 0 and @newDayOfWeek < @originalDayOfWeek then 2
            else 0
        end
    
        -- Return the result of the function
        return dateadd(d, @daysToAdd + @dateOffset, dateadd(ww, @weeksToAdd, @date))
    
    END
    
  19. ==============================

    19.난 그냥 허용 대답을 시험하고 일요일 시작 날 때 작동하지 않는 것을 발견했다.

    난 그냥 허용 대답을 시험하고 일요일 시작 날 때 작동하지 않는 것을 발견했다.

    당신은 선택 @Saturday 라인 항목 아래에 다음을 추가해야합니다 :

    SELECT @fromDate = CASE WHEN DATEPART(weekday,@fromDate) = 1 THEN DATEADD(day,1,@fromDate) ELSE @fromDate END
    
  20. ==============================

    20.한숨. 여기에) 마이크로 소프트 SQL 서버 (Microsoft는 영원히 Excel에서 근무 기능을했다하더라도)와 b) 맑은 용액의 표준 "DateAddWorkDays을"또는 다른 곳에서도 나는 것을 찾을 수 있습니다 나는 이러한 모든 년 후가 더 아직도 믿을 수 없다 사람들이 제기 한 모든 문제를 처리합니다.

    한숨. 여기에) 마이크로 소프트 SQL 서버 (Microsoft는 영원히 Excel에서 근무 기능을했다하더라도)와 b) 맑은 용액의 표준 "DateAddWorkDays을"또는 다른 곳에서도 나는 것을 찾을 수 있습니다 나는 이러한 모든 년 후가 더 아직도 믿을 수 없다 사람들이 제기 한 모든 문제를 처리합니다.

    여기에 내가 여기에 보이는 모든 주소를 위의 답변을 다음과 같은 문제를 개발하고 다른 곳에서 내가 발견 할 수있었습니다 솔루션은 하나 이상의했다입니다. 이 핸들 :

    제안 : 물론, 어떤 재귀 알고리즘으로,이 하나 (임시 테이블 즉, 자신의 스택을 구현하여) 반복적 하나에 변환 할 수 있습니다,하지만 난 32 개 중첩 수준이 대부분을위한 충분한보다 방법이 더 생각 실제 사용 사례. 또한, 물론, 당신은 하드 코드 표 참조 대 테이블 반환 매개 변수로 작동하지 않는 평일 날짜에 전달하여 더 / 일반 휴대 할 수 있습니다.

    SET ANSI_NULLS ON
    GO
    
    SET QUOTED_IDENTIFIER ON
    GO
    
    -- ===================================================================================================================================
    -- Author:      Tom
    -- Create date: 03/13/2017
    -- Description: Add specified # of working days (+/-) to a specified date-time assuming existence of a list of non-work weekday 
    --  dates (incl. holidays, weather days, utility outage days, fire days, etc.) in the 'NonWorkDayDate' Column of a 'NonWorkWeekday' 
    --  Table. If specified # working days is 0, the specified date-time is returned.  Working days are not added until the specified 
    --  date-time has first been incremented (+/-) to the next working day in the direction of the working days increment.
    --  NOTE: Uses a forumla (vs. O(n) loop) that uses recusion whenever days incremented (incl. weekends) spans non-work weekdays.
    --  !!!WARNING!!!: Will exceed SQL Server nesting level (32) if abs (# of working days) < ~1 / 32 adjacent non-working days.
    -- Parameters:
    --  @RefDateTime    DateTime:   Reference date-time to which to add '@WorkDaysIncrement'.
    --  @WorkDaysIncrement  Int:    # of working days (+/-) to add # to the '@RefDateTime'.
    -- Returns:
    --  1. Result of @RefDateTime + @WorkDaysIncrement (skipping weekend and holiday dates and retaining the @RefDateTime's time).
    -- ===================================================================================================================================
    CREATE FUNCTION [dbo].[AddWorkDays_Recursive] 
    (
        -- Add the parameters for the function here
        @RefDateTime datetime,
        @WorkDaysIncrement int
    )
    RETURNS DateTime
    AS
    BEGIN
    
    -- If no days to increment, return passed in date-time (even if weekend day).
        if (@WorkDaysIncrement = 0) return @RefDateTime
    
    -- Set the one-day increment used to add or subtract one calendar/work day.
        declare @OneDayIncrement int = sign(@WorkDaysIncrement)
    
    -- Initialize # of calendar days added to 0.
        declare @DaysAdded int = 0
    
    -- Set reference date to date (i.e. excl. time) of reference date-time.
        declare @RefDate datetime = convert
            (
                date,
                convert
                (
                    varchar(10),
                    @RefDateTime,
                    101
                )
            ) 
        --end declare @RefDate 
    
    -- Initialize result date to reference date
        declare @ResultDate datetime = @RefDate
    
    -- Set U.S. Weekday # to the 1-based U.S. weekday # result date.
        declare @USWeekdayNumber tinyint = ((datepart(weekday, @ResultDate) + @@datefirst - 1) % 7) + 1 -- Sun to Sat = 1 to 7
    
    -- If result date is now on a weekend day, set #  of weekend days increment so that we can move it +/- 1 to 2 days to next weekday.
        declare @WeekendDaysInc smallint = 
        (
            case (@USWeekdayNumber)
    
                when 1 then --Sunday 
                    case
                        when (@OneDayIncrement > 0) then 1
                        else -2 
                    end 
                --end when 1 --Sunday
    
                when 7 then --Saturday 
                    case
                        when (@OneDayIncrement > 0) then 2
                        else -1
                    end 
                --end when 7 then --Saturday 
    
                else 0 -- Not Weekend Day #
    
            end -- case (@USWeekdayNumber)
        ) -- end declare @WeekendDaysInc smallint = 
    
    -- Increment # of calendar days added by #  of weekend days increment
        set @DaysAdded += @WeekendDaysInc
    
    -- Increment result date by #  of weekend days increment
        set @ResultDate += @WeekendDaysInc 
    
    -- Set # of work weeks increment to # of full 5-day increments in the # (+/-) of work days to increment.
        declare @WorkWeeksIncrement int = @WorkDaysIncrement / 5
    
    -- Increment # of calendar days added by 7 times # of work weeks increment, i.e. to add weekday + weekend days for full weeks.
        set @DaysAdded += @WorkWeeksIncrement * 7
    
    -- Set result date after full weeks added to reference date + # of calendar days 
        declare @AfterFullWeeksResultDate datetime = @ResultDate + @DaysAdded
    
    -- Set # partial-work week days to # (+/-) of work days to increment left after adding full weeks.
        declare @PartialWorkWeekDays int = @WorkDaysIncrement % 5
    
    -- Increment # of calendar days added by # partial-work week days
        set @DaysAdded += @PartialWorkWeekDays
    
    -- Set result date after partial week added to result date after full weeks added + # partial work week days
        declare @AfterPartialWeekResultDate datetime = @AfterFullWeeksResultDate + @PartialWorkWeekDays
    
    --Set result date to result date after partial week.
        set  @ResultDate = @AfterPartialWeekResultDate
    
    -- Set After Full Weeks U.S. Weekday # to the 1-based U.S. weekday # result date.
        declare @AfterFullWeeksUSWeekdayNumber tinyint = 
            (
                ((datepart(weekday, @AfterFullWeeksResultDate) + @@datefirst - 1) % 7) + 1 -- Sun to Sat = 1 to 7
            )
    
    -- Set After Partial Week U.S. Weekday # to the 1-based U.S. weekday # result date.
        declare @AfterPartialWeekUSWeekdayNumber tinyint = 
            (
                ((datepart(weekday, @AfterPartialWeekResultDate) + @@datefirst - 1) % 7) + 1 -- Sun to Sat = 1 to 7
            )
    
    --If (incrementing and After Full Weeks U.S. Weekday # > @AfterPartialWeekUSWeekdayNumber) 
    --  or (decrementing and After Full Weeks U.S. Weekday # < @AfterPartialWeekUSWeekdayNumber), increment by (+/-) 2 to account for 
    --  the weekend that was spanned when partial-work week days were added.
        if 
        (
            (
                (@OneDayIncrement > 0)
                and (@AfterFullWeeksUSWeekdayNumber > @AfterPartialWeekUSWeekdayNumber)
            )
            or (
                (@OneDayIncrement < 0)
                and (@AfterFullWeeksUSWeekdayNumber < @AfterPartialWeekUSWeekdayNumber)
            )
    
        )
        begin
            set @WeekendDaysInc = 2 * @OneDayIncrement
            set @DaysAdded += @WeekendDaysInc
            set @ResultDate += @WeekendDaysInc
        end -- if need to increment to account for weekend spanned by partial-work week days,
    
    -- Set U.S. Weekday # to the 1-based U.S. weekday # result date.
        set @USWeekdayNumber = ((datepart(weekday, @ResultDate) + @@datefirst - 1) % 7) + 1 -- Sun to Sat = 1 to 7
    
    -- If result date is now on a weekend day, set #  of weekend days increment so that we can move it +/- 1 to 2 days to next weekday.
        set @WeekendDaysInc = 
        (
            case (@USWeekdayNumber)
    
                when 1 then --Sunday 
                    case
                        when (@OneDayIncrement > 0) then 1
                        else -2 
                    end 
                --end when 1 --Sunday
    
                when 7 then --Saturday 
                    case
                        when (@OneDayIncrement > 0) then 2
                        else -1
                    end 
                --end when 7 then --Saturday 
    
                else 0 -- Not Weekend Day #
    
            end -- case (@USWeekdayNumber)
        ) -- end declare @WeekendDaysInc smallint = 
    
    -- Increment # of calendar days added by #  of weekend days increment
        set @DaysAdded += @WeekendDaysInc
    
    -- Increment result date by #  of weekend days increment
        set @ResultDate += @WeekendDaysInc 
    
    -- Set non-work weedays count to # Rows where NonWorkDayDate between RefDate and ResultDate (if # of work days to increment > 0), else between 
    --  ResultDate and RefDate.
        declare @NonWorkWeekdaysCount int =
        (
            select count(nw.NonWorkDayDate) 
                from NonWorkWeekday as nw
                where 
                    (
                        (@OneDayIncrement > 0)
                        and (nw.NonWorkDayDate between @RefDate and @ResultDate)
                    )
                    or (
                        (@OneDayIncrement < 0)
                        and (nw.NonWorkDayDate between @ResultDate and @RefDate)
                    )
            --end select count(nw.NonWorkDayDate) from Holidate as nw 
        ) -- end declare @HolidaysSpanned int =
    
    -- Set result date-time to reference date-time + # of calendar days added
        declare @ResultDateTime datetime = @RefDateTime + @DaysAdded 
    
    -- Set result date-time equal to result of adding (# of holidays x one-day increment).
        set @ResultDateTime = dbo.AddWorkDays_Recursive
            (
                @ResultDateTime, -- @RefDateTime
                @NonWorkWeekdaysCount * @OneDayIncrement -- @WorkDaysIncrement
            )
        --end set @ResultDateTime = 
    
        -- Return the result of the function
        RETURN @ResultDateTime
    
    END
    
    GO
    
  21. ==============================

    21.독일의 경우, 모든 응답이 작동하지 않습니다.

    독일의 경우, 모든 응답이 작동하지 않습니다.

    나는 시험하고 작동하는 유일한 기능은 여기에 오래된 엑셀 양식에서 번역 한 것입니다 :

    Set @EndDate=Dateadd(DAY,@DaysToAdd,@FromDate) +
    Cast(((
             CASE WHEN 5 <= DATEPART(weekday, @FromDate)%7 
            THEN 5
             ELSE 
             DATEPART(weekday, @FromDate)%7
             END)
          -1 + @DaysToAdd )/5 
     as int) 
    * 2 - 
       (Case when DAtepart(weekday, @FromDate)=6 then 1 else 0 end) 
    
  22. ==============================

    22.의 방향에 따라 그 주말 또는 가까운 평일에 변화에서 시작 : 내 원래 대답을 --Refactoring ... 나는 시작 날짜가 주말로 발생하는 경우 계산의 시작점을 정의하는 옵션을 추가했습니다 델타.

    의 방향에 따라 그 주말 또는 가까운 평일에 변화에서 시작 : 내 원래 대답을 --Refactoring ... 나는 시작 날짜가 주말로 발생하는 경우 계산의 시작점을 정의하는 옵션을 추가했습니다 델타.

    DECLARE
        @input DATE = '2019-06-15', -- if null, then returns null
        @delta INT = 1, -- can be positive or negative; null => zero
        @startFromWeekend BIT = 1 -- null => zero
    
    -- input is null, delta is zero/null
    IF @input IS NULL OR ISNULL(@delta, 0) = 0
        SELECT @input
    
    -- input is not null and has delta
    ELSE
    BEGIN
        DECLARE
            @input_dw INT = (DATEPART(DW, @input) + @@DATEFIRST - 1) % 7, -- input day of week
            @weeks    INT = @delta / 5, -- adjust by weeks
            @days     INT = @delta % 5  -- adjust by days
    
        -- if input is a weekend day, offset it for proper calculation
        -- !!important!!: depends on *your* definition of the starting date to perform calculation from
        DECLARE @offset INT =
            -- start calc from weekend day that is nearest to a weekday depending on delta direction
            -- pos delta: effectively Sunday of the weekend   (actual: prev Friday)
            -- neg delta: effectively Saturday of the weekend (actual: next Monday)
            CASE WHEN ISNULL(@startFromWeekend, 0) = 1
            THEN CASE WHEN @delta > 0
                THEN CASE @input_dw
                    WHEN 0 THEN -2
                    WHEN 6 THEN -1
                    END
                ELSE CASE @input_dw
                    WHEN 0 THEN  1
                    WHEN 6 THEN  2
                    END
                END
            -- start calc from nearest weekday depending on delta direction
            -- pos delta: next Monday from the weekend
            -- neg delta: prev Friday from the weekend
            ELSE CASE WHEN @delta > 0
                THEN CASE @input_dw
                    WHEN 0 THEN  1
                    WHEN 6 THEN  2
                    END
                ELSE CASE @input_dw
                    WHEN 0 THEN -2
                    WHEN 6 THEN -1
                    END
                END
            END
    
        -- calculate: add weeks, add days, add initial correction offset
        DECLARE @output DATE = DATEADD(DAY, @days + ISNULL(@offset, 0), DATEADD(WEEK, @weeks, @input))
    
        -- finally, if output is weekend, add final correction offset depending on delta direction
        SELECT
            CASE WHEN (DATEPART(DW, @output) + @@DATEFIRST - 1) % 7 IN (0,6)
            THEN CASE 
                WHEN @delta > 0 THEN DATEADD(DAY,  2, @output)
                WHEN @delta < 0 THEN DATEADD(DAY, -2, @output)
                END
            ELSE @output
            END
    END
    
  23. ==============================

    23.테스트 / 2012 2008 년 큰 작업 - 나는 아주 최근 @DaysToAdd int 값을 생성하여 현재 날짜로이 일을 추가하려면이 문제를 해결했습니다.

    테스트 / 2012 2008 년 큰 작업 - 나는 아주 최근 @DaysToAdd int 값을 생성하여 현재 날짜로이 일을 추가하려면이 문제를 해결했습니다.

    DECLARE @DaysToAdd INT
    
    SELECT @DaysToAdd = CASE  
       WHEN DATEPART(WEEKDAY,GETDATE()) =  1 THEN 3 -- Sunday -> Wednesday
       WHEN DATEPART(WEEKDAY,GETDATE()) =  5 THEN 4 -- Thursday -> Monday
       WHEN DATEPART(WEEKDAY,GETDATE()) =  6 THEN 4 -- Friday -> Tuesday
       WHEN DATEPART(WEEKDAY,GETDATE()) =  7 THEN 4 -- Saturday -> Wednesday
       ELSE 2 END
    
    SELECT DATEADD(DAY, @DaysToAdd, GETDATE()) AS TwoWorkingDaysTime
    
  24. from https://stackoverflow.com/questions/5471524/add-business-days-to-date-in-sql-without-loops by cc-by-sa and MIT license