Добавьте рабочие дни в 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 ]

0 голосов
/ 25 марта 2015

Эта функция SQL работает аналогично функции Excel 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

Ссылка

0 голосов
/ 15 октября 2015

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

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

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
0 голосов
/ 21 августа 2015

Для Германии все ответы не работают.

Единственная функция, которую я протестировал и работает, - это перевод из старой формы Excel здесь :

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