Вопрос

У меня есть таблица дат под названием [BadDates], в ней есть только один столбец, где каждая запись представляет собой дату, которую нужно исключить.У меня есть UDF следующим образом:

CREATE FUNCTION [dbo].[udf_GetDateInBusinessDays]
(
  @StartDate datetime,  --Start Date
  @NumberDays int           --Good days ahead
)
RETURNS datetime
AS
BEGIN
-- Declare the return variable here
DECLARE @ReturnDate datetime
SET @ReturnDate = @StartDate
DECLARE @Counter int
SET @Counter = 0
WHILE   @Counter < @NumberDays
BEGIN
    SET @ReturnDate = DateAdd(d,1,@ReturnDate)
    IF ((SELECT COUNT(ID)
        FROM dbo.[BadDates]
        WHERE StartDate = @ReturnDate) = 0)
    BEGIN
        SET @Counter = @Counter + 1
    END
END
RETURN @ReturnDate
END

Этот UDF работает отлично, но обрабатывается медленно.Хранимая процедура, использующая это, запускает пользовательскую функцию в каждой записи.Есть ли другие способы обеспечить эту же функциональность более быстрым способом.

Любая помощь очень ценится!

Это было полезно?

Решение

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

CREATE FUNCTION [dbo].[udf_GetDateInBusinessDays]
(
  @StartDate datetime,  --Start Date
  @NumberDays int           --Good days ahead
)
RETURNS datetime
AS
BEGIN
-- Declare the return variable here
DECLARE @ReturnDate datetime
SET @ReturnDate = dateadd(d, @NumberDays, @StartDate);


DECLARE @d int;
SET @d = (select count(1) from baddates where startdate >= @StartDate and startdate <= @ReturnDate);

declare @t datetime;

WHILE   @d > 0
BEGIN
    set @t = @ReturnDate;
    set @ReturnDate = dateadd(d, @d, @ReturnDate);
    SET @d = (select count(1) from baddates where startdate > @t and startdate <= @ReturnDate);
END

RETURN @ReturnDate
END

Другие советы

Я предполагаю, что вы пытаетесь вычислить дату, которая составляет x рабочих дней после заданной даты.какая дата будет через 10 рабочих дней от сегодняшнего дня.Я также предполагаю, что ваша таблица baddates содержит нерабочие дни, например.Выходные и праздничные дни.

Я сталкивался с подобными требованиями в прошлом и обычно получал таблицу дней, содержащую все возможные даты, а также флаг, указывающий, является ли конкретная дата рабочим днем ​​или нет.

Затем я использую эту таблицу, чтобы вычислить дату, которая равна x рабочих дней от указанной даты, выбирая запись, которая находится через x дней после начальной даты.

Итак, что-то вроде этого

 CREATE TABLE all_days (  
  dated DATETIME,  
  day_state CHAR(1)  
  )

Где day_state — значение
Д - Рабочий день
В – выходные
B – праздничный день

SQL для поиска даты через x рабочих дней становится

SELECT MAX(dated)
FROM (
  SELECT TOP(@number_days) dated
  FROM all_days
  WHERE day_state = 'D'
  AND dated >= @start_date
  ORDER by dated ASC
)

Этот код не проверен, но должен дать вам общее представление.Возможно, вы не захотите проводить различие между выходными и праздничными днями, и в этом случае вы можете переименовать day_state вwork_day и сделать его полем BIT.

Вам следует создать составной уникальный индекс для дат и дней_состояния.

Возможно, вы захотите поместить индекс в BadDates.StartDate, но могут быть и другие, лучшие решения.

Хорошо, почему вы считаете, когда можете использовать ключевое слово EXISTS?Если это потому, что в Badates может быть несколько дат одного типа, это кажется неправильным.COUNT, вероятно, просматривает всю таблицу, чтобы подсчитать экземпляры startdate, тогда как для исключения вам нужно всего лишь 1.

Вы просмотрели план запроса, чтобы увидеть, что происходит?

Похоже, вы используете эту UDF для вычисления разницы между двумя датами.Если я правильно интерпретирую это, я бы рекомендовал вам использовать встроенную функцию dateiff.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top