SQL функция застряла в цикле - PullRequest
0 голосов
/ 28 мая 2020

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

Я немного новичок в функциях в SQL и считаю, что мои logi c - это нормально, но я застрял.

У меня есть 2 стола, которые я сделал. Один содержит все даты выходных, а другой - все праздничные даты. Функция предназначена для того, чтобы принимать одну дату, а затем с помощью двух циклов while вычислять за 3 рабочих дня до даты отправки, а затем возвращать эту новую дату в мой оператор выбора.

Вот функция в вопросе:

FUNCTION [dbo].[lessThreeBD](@WORKING_DT DATE)  
RETURNS DATE   
AS  
BEGIN
DECLARE @ThreeBD DATE
DECLARE @COUNTER INT
SET @COUNTER = 0

WHILE @COUNTER < 4
SET @ThreeBD = @WORKING_DT
BEGIN
    WHILE CASE WHEN (SELECT TOP 1 HOL.DATE from DATABASE.dbo.Holidays HOL where HOL.DATE = CAST(@WORKING_DT AS DATE)) IS NULL THEN 'NOT HOLIDAY' ELSE 'HOLIDAY' END = 'HOLIDAY'
    OR CASE WHEN (SELECT TOP 1 WKND.DATE from DATABASE.dbo.Weekends WKND where WKND.DATE = CAST(@WORKING_DT AS DATE)) IS NULL THEN 'WEEKDAY' ELSE 'WEEKEND' END = 'WEEKEND'
    BEGIN
        SET @WORKING_DT = DATEADD(DAY, -1, @WORKING_DT)
    END
    SET @WORKING_DT = DATEADD(DAY, -1, @WORKING_DT)
    SET @COUNTER  = @COUNTER + 1
SET @ThreeBD = @WORKING_DT
END
RETURN @ThreeBD
END

Однако, когда я тестирую это с одной датой, кажется, что он заблокирован:

Тестовая строка:

SELECT DATABASE.dbo.lessThreeBD('2020-05-24') AS TESTING

Эта строка должна возвращать 20-е число.

Есть идеи, что я здесь делаю не так?

Имейте в виду, что и праздничные, и выходные столы работают отлично. Я уже протестировал операторы case и получаю ожидаемые результаты с каждым оператором case.

Ответы [ 3 ]

2 голосов
/ 28 мая 2020

Это

WHILE @COUNTER < 4
SET @ThreeBD = @WORKING_DT

эквивалентно

WHILE @COUNTER < 4
BEGIN
  SET @ThreeBD = @WORKING_DT
END

, которое является бесконечным l oop.

Всегда используйте BEGIN / END с операторами потока управления в T SQL.

WHILE @COUNTER < 4
BEGIN
  SET @ThreeBD = @WORKING_DT
  BEGIN
. . .

За исключением, возможно, таких распространенных идиом, как

if @@trancount > 0 rollback;
0 голосов
/ 28 мая 2020

После исправления нулевой проблемы и проблемы с SET, не находящейся внутри BEGIN, мне пришлось внести еще пару изменений, чтобы эта работа была точной.

Последняя функция выглядит следующим образом для всех, кто хотел бы для собственного использования:

FUNCTION [dbo].[lessThreeBD](@WORKING_DT DATE)  
RETURNS DATE   
AS  
BEGIN
    DECLARE @COUNTER INT
    SET @COUNTER = 0

    WHILE @COUNTER < 3
    BEGIN
        SET @WORKING_DT = DATEADD(DAY, -1, @WORKING_DT)
        SET @COUNTER  = @COUNTER + 1
        WHILE (SELECT SQL_VARIANT_PROPERTY((SELECT TOP 1 HOL.DATE as CT from crmCAST.dbo.Holidays HOL where HOL.DATE = CAST(@WORKING_DT AS DATE)), 'BaseType')) IS NOT NULL
        OR (((DATEPART(DW, @WORKING_DT) - 1 ) + @@DATEFIRST ) % 7) IN (0,6)
        BEGIN
            SET @WORKING_DT = DATEADD(DAY, -1, @WORKING_DT)
        END
    END
RETURN @WORKING_DT
END

Мне удалось удалить свою таблицу выходных дней с помощью (((DATEPART(DW, @WORKING_DT) - 1 ) + @@DATEFIRST ) % 7) IN (0,6), которая сообщит мне, является ли дата выходным, поэтому единственное, что вам понадобится, это таблица, имеет список праздников, которые отмечает ваша компания, поэтому вы можете получить точную прибыль за 3 рабочих дня.

0 голосов
/ 28 мая 2020

Думаю, проблема здесь:

WHILE @COUNTER < 4 SET @ThreeBD = @WORKING_DT BEGIN

эта команда SET выполняется в бесконечном l oop.

...