Добавьте рабочие дни в SQL без циклов - PullRequest
30 голосов
/ 29 марта 2011

В настоящее время в моей базе данных SQL есть функция, которая добавляет определенное количество рабочих дней к дате, например, если вы введете дату, которая является четвергом, и добавите два дня, будет возвращена дата следующего понедельника. Я не беспокоюсь о каких-либо праздниках, исключены только выходные.

Проблема заключается в том, что в настоящее время это выполняется с использованием цикла while, и, похоже, оно значительно замедляет хранимую процедуру, которая использует ее при создании таблицы. Кто-нибудь знает, есть ли способ выполнить этот расчет без циклов 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

Ответы [ 23 ]

1 голос
/ 20 сентября 2012

Принятый ответ на вопрос дает неверные результаты. Например. select @fromDate = '03-11-1983', @DaysToAdd = 3 приводит к 03-14-1983, тогда как 03-16-1983 - ожидаемое .

Я разместил рабочее решение здесь , но для полноты я также добавлю его сюда. Если вас интересуют подробности двух методов, посетите мой оригинальный ответ. Если нет, просто скопируйте / вставьте это в ваш проект 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
)
1 голос
/ 11 июля 2012

Спасибо Дэмиену за код.В кальках произошла небольшая ошибка, так как в воскресенье она добавляла только 1 день, а когда число рабочих дней пересекало выходные (но не приходилось на выходные), дополнительные 2 дня не учитывались.Вот модифицированная версия кода Damiens, которая работает с datefirst по умолчанию в 7. Надеюсь, это поможет.

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
1 голос
/ 08 июля 2015

Я протестировал все предложенные здесь решения, и ни одно из них не работает.Вот несколько тестовых сценариев, которые сломали множество вышеперечисленных решений.(при условии, что суббота и воскресенье - дни, которые вы исключаете):

-Добавить 0 дней к субботе - Ожидаемый результат = суббота

-Добавить 0 дней к воскресенью - Ожидаемый результат = воскресенье

-Добавить 1 день в пятницу - Ожидаемый результат = следующий понедельник

-Добавить 1 день в субботу - Ожидаемый результат = следующий понедельник

-Добавить 1 день в воскресенье -Ожидаемый результат = следующий понедельник

-Добавить 3 дня к пятнице - Ожидаемый результат = следующая среда

-Добавить 5 дней к субботе - Ожидаемый результат = следующая пятница

-Добавить 5 дней к пятнице - Ожидаемый результат = следующая пятница

-Вычитать 1 день из понедельника - Ожидаемый результат = предыдущая пятница

-Вычитать 1 день из воскресенья - Ожидаемый результат = предыдущаяПятница

- вычитать 1 день с субботы - ожидаемый результат = предыдущая пятница

- вычитать 3 дня с понедельника - ожидаемый результат = предыдущая среда

- вычитать 5 днейс субботы - ожидаемый результат = предыдущий понедельник

- вычесть 5 дней с понедельника - ожидаемый результат = предыдущий понедельник

Вот что я написал после прочтения всей этой цепочки и выбора хороших вещейлогики:

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
1 голос
/ 16 октября 2018

Это старая ветка, но я только что создал таблицу со всеми датами и сделал следующее:

SELECT Count(*) 
FROM Date_Table
WHERE [day] BETWEEN @StartDate and @EndDate
    AND DATENAME(weekday, [day]) NOT IN ('Sunday', 'Saturday')
1 голос
/ 13 ноября 2015
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) 
0 голосов
/ 28 июня 2014

Я знаю, что уже немного поздно, возможно, кто-то еще наткнулся на эту проблему.Я пробовал вышеупомянутое решение, но большинство из них не может рассчитать праздничные дни.

Вот как я пытался

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 - это таблица с праздничной датой в качестве ссылки на выходной

Надеюсь, это кому-нибудь поможет.

0 голосов
/ 27 апреля 2018

- Рефакторинг моего исходного ответа ... Я добавил опцию, чтобы определить начальную точку вычисления, если начальная дата оказывается выходным днем: начать с этого выходного дня или перейти к ближайшему рабочему дню в зависимости от Направление дельты.

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
0 голосов
/ 14 марта 2017

Вздох. Я не могу поверить, что после всех этих десятилетий существует все еще нет: а) стандартный «DateAddWorkDays» в Microsoft SQL Server (даже если у Microsoft всегда была функция WorkDay в Excel) и б) четкое решение в Здесь или где-либо еще я могу найти, что решает все вопросы, которые люди подняли.

Вот решение, которое я разработал и которое решает следующие проблемы, которые, по-видимому, на все приведенные выше ответы здесь и в других местах, которые мне удалось найти, содержат одно или несколько из них. Это обрабатывает:

  1. Имена мнемонических идентификаторов.
  2. Комментарии, объясняющие код, который не ясен.
  3. Не проверять каждый рабочий день, который нужно увеличивать (т.е. намного меньше, чем сложность O (n)).
  4. Отрицательный прирост рабочего дня.
  5. Допускается передача части времени, не относящейся к 12 часам утра (так что вам не придется сначала ее удалять).
  6. Сохранение переданного временного отрезка, если он есть, в результате (в случае, если вам нужно точное время x рабочих дней вперед / назад).
  7. Названия выходных дней на языках, отличных от английского.
  8. @@ DateFirst значения, отличные от значений по умолчанию (7 или США).
  9. Указание пользовательского списка нерабочих выходных.
  10. Разрешение на работу в нерабочие дни выходного дня, если дата заезда не в 12:00.
  11. Возвращение начальной даты-времени, если приращение # рабочих дней равно 0, даже если начальная дата-время находится в нерабочий день.
  12. Сначала переходите к следующему / предыдущему рабочему дню, прежде чем начинать увеличивать / уменьшать рабочие дни соответственно. ПРИМЕЧАНИЕ. Это отличается от функции WorkDay в Excel, но я считаю, что это более полезно и интуитивно понятно. Ex. Если вы получаете запрос / заказ в выходные дни, и у вас есть SLA (т.е. время ответа, дата доставки) в течение 1 рабочего дня, вам не нужно отвечать / доставлять, пока не пройдет 1 полный рабочий день (независимо от того, как ему предшествовало много соседних нерабочих дней).
  13. Пропуск любых дополнительных выходных и / или нерабочих рабочих дней, которые могли быть добавлены после добавления любых нерабочих рабочих дней назад, которые могли быть добавлены при добавлении начальных выходных дней при добавлении только # рабочих дней - и повторяться до тех пор, пока нет дольше необходимо.

ПРЕДЛОЖЕНИЯ: Конечно, как и в любом рекурсивном алгоритме, этот можно преобразовать в итеративный (путем реализации собственного стека, то есть с помощью Temp Table), но я думаю, что 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
0 голосов
/ 03 февраля 2017

Я только что проверил принятый ответ и обнаружил, что он не работает, когда воскресенье - день начала.

В позицию Select @Saturday необходимо добавить следующее:

SELECT @fromDate = CASE WHEN DATEPART(weekday,@fromDate) = 1 THEN DATEADD(day,1,@fromDate) ELSE @fromDate END
0 голосов
/ 21 июня 2016

Я совсем недавно решил эту проблему, добавив два рабочих дня к текущей дате, создав значение INT @DaysToAdd - протестировано и отлично работает в 2008/2012 годах.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...