[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.이 승인 된 이후 원본이 잘못 때문에 대답은 크게 변경되었습니다. 그래도 새 쿼리에 더 확신, 그리고 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.사람이 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.이 질문에 허용 된 대답의 오프 구축, 다음과 같은 사용자 정의 함수 (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.이 답변은 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.당신에 대해 생각 미리 채우는 예를 들어 WorkingDays (INT의 DaySequenceId, 날짜 WorkingDate)에 대해, (함수를 사용) 일을 모두 포함하는 룩업 테이블은, 당신은 다음 @fromDate의 DaySequenceId을 선택하여이 테이블을 사용할 수 있습니다 새로운 작업 날짜를 얻을 수 @daysToAdd를 추가합니다. 물론이 방법은 또한 WorkingDays 테이블을 관리의 추가 오버 헤드를 가지고 있지만, 당신은 당신이 기대하는 날짜의 범위를 미리 채울 수 있습니다. 다른 단점은 단지 WorkingDays 테이블에 포함 된 것이어야합니다 계산 될 수있는 작업 날짜입니다.
당신에 대해 생각 미리 채우는 예를 들어 WorkingDays (INT의 DaySequenceId, 날짜 WorkingDate)에 대해, (함수를 사용) 일을 모두 포함하는 룩업 테이블은, 당신은 다음 @fromDate의 DaySequenceId을 선택하여이 테이블을 사용할 수 있습니다 새로운 작업 날짜를 얻을 수 @daysToAdd를 추가합니다. 물론이 방법은 또한 WorkingDays 테이블을 관리의 추가 오버 헤드를 가지고 있지만, 당신은 당신이 기대하는 날짜의 범위를 미리 채울 수 있습니다. 다른 단점은 단지 WorkingDays 테이블에 포함 된 것이어야합니다 계산 될 수있는 작업 날짜입니다.
-
==============================
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.아민의 의견이에 한 줄의 솔루션입니다, 위의 네이트 요리사의 대답에 확장하려면 :
아민의 의견이에 한 줄의 솔루션입니다, 위의 네이트 요리사의 대답에 확장하려면 :
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.
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.나는 시험에 순간에는 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.코드 주셔서 감사합니다 데미안. 거기는 일요일에만 일일를 추가한다는 점에서 약간의 오류가 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.질문의 허용 대답은 잘못된 결과를 얻을 수 있습니다. 예를 들면 선택 @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.이것은 내가 무엇을 사용 :
이것은 내가 무엇을 사용 :
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.나는 모든 솔루션이 여기에 제시하지 않고 그 일의 아무도 테스트했습니다. 다음은 위의 방법을 많이 부러 몇 가지 테스트 시나리오입니다. (토, 일 가정은 제외하는 일입니다) :
나는 모든 솔루션이 여기에 제시하지 않고 그 일의 아무도 테스트했습니다. 다음은 위의 방법을 많이 부러 몇 가지 테스트 시나리오입니다. (토, 일 가정은 제외하는 일입니다) :
토요일에 - 추가 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.
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.이 오래된 스레드하지만 난 그냥 이런 짓을 한 후 모든 날짜와 테이블을 생성 :
이 오래된 스레드하지만 난 그냥 이런 짓을 한 후 모든 날짜와 테이블을 생성 :
SELECT Count(*) FROM Date_Table WHERE [day] BETWEEN @StartDate and @EndDate AND DATENAME(weekday, [day]) NOT IN ('Sunday', 'Saturday')
-
==============================
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.이 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.나는 조금 늦게 파티에 있어요하지만 난 때문에 다른 솔루션의 단점이 내 자신의 버전을 작성 감아. 특히이 버전 주소는 거꾸로 계산하고, 주말에 시작.
나는 조금 늦게 파티에 있어요하지만 난 때문에 다른 솔루션의 단점이 내 자신의 버전을 작성 감아. 특히이 버전 주소는 거꾸로 계산하고, 주말에 시작.
당신이 주말 날짜 제로 일을 추가 할 경우, 발생할 수있는 모호한 상황이있다. 나는 날짜를 동일하게 유지했지만, 당신은 항상 반환 할 평일을 강제하려는 경우 당신은이 검사를 생략 할 수 있습니다.
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.난 그냥 허용 대답을 시험하고 일요일 시작 날 때 작동하지 않는 것을 발견했다.
난 그냥 허용 대답을 시험하고 일요일 시작 날 때 작동하지 않는 것을 발견했다.
당신은 선택 @Saturday 라인 항목 아래에 다음을 추가해야합니다 :
SELECT @fromDate = CASE WHEN DATEPART(weekday,@fromDate) = 1 THEN DATEADD(day,1,@fromDate) ELSE @fromDate END
-
==============================
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.독일의 경우, 모든 응답이 작동하지 않습니다.
독일의 경우, 모든 응답이 작동하지 않습니다.
나는 시험하고 작동하는 유일한 기능은 여기에 오래된 엑셀 양식에서 번역 한 것입니다 :
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.의 방향에 따라 그 주말 또는 가까운 평일에 변화에서 시작 : 내 원래 대답을 --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.테스트 / 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
from https://stackoverflow.com/questions/5471524/add-business-days-to-date-in-sql-without-loops by cc-by-sa and MIT license
'SQL' 카테고리의 다른 글
[SQL] 값이 이미 피할 중복에 존재하는지 확인하는 방법? (0) | 2020.06.06 |
---|---|
[SQL] 오라클 11g - 정규식 체크 제약 조건 (0) | 2020.06.06 |
[SQL] WHERE NULL이 절은 SQL Server 매개 변수 값에 따라 NULL 또는 NO가 없습니다 (0) | 2020.06.06 |
[SQL] 오라클 SQL : 다른 삽입 존재 업데이트하는 경우 [중복] (0) | 2020.06.05 |
[SQL] SQL에서 두 행을 병합 (0) | 2020.06.05 |