CTE рекурсия бесконечный цикл - PullRequest
0 голосов
/ 28 марта 2019

Я работаю с хранимой процедурой и использую CTE в SQL Server и пытаюсь получить некоторые данные из двух таблиц, но когда выполнение переходит к запросу CTE, оно получает бесконечный цикл и никогда не заканчивается,Есть ли способ предотвратить этот бесконечный цикл?

Это запрос, который я создаю:

WITH tableName(Id, enddate, statusDte, closeId, shceDte, calcDte, closeEndDte, ParentId, LastClose, lasCloseDte, closeClass,addSe,twon,code)
AS
(
    SELECT 
        tba.Id,
        CASE WHEN tb.ParentId IS NOT NULL 
                THEN tb.Id
             WHEN tb.statusDte IN (1,2,3) 
                THEN  tb.calcDte ELSE tb.shceDte 
                END ForecastDueDate, 
        statusDte, closeId, shceDte, calcDte, 
        CASE WHEN tb.ParentId IS NULL 
                THEN closeEndDte ELSE NULL END, tb.ParentId, 0, 
        CASE WHEN tb.ParentId IS NOT NULL 
                THEN statusDte
             WHEN tb.statusDte = 5
             AND (tb.calcDte BETWEEN '1/1/2020 12:00:00 AM' AND '12/31/2020 11:59:59 PM' 
             OR tb.closeEndDte BETWEEN '1/1/2020 12:00:00 AM' AND '12/31/2020 11:59:59 PM') 
                THEN ams.GetPreviousNthFullAuditDate(tb.Id, tb.AuditID, 2)  ELSE a.statusDate END as lastDate,
        a.closeClass, tba.addSe,tba.town,tba.code
    FROM 
        tableA tba 
    INNER JOIN 
        tableB tb ON tb.Id = tba.Id 
    WHERE 
        statusDte NOT IN (3,4) AND tba.IsAtve = 1

    UNION ALL

    SELECT 
        Id, enddate, 
        statusDte, statusDte, shceDte, calcDte, closeEndDte, ParentId,
        0, lasCloseDte, closeClass,addSe,twon,code
    FROM 
        tableName
    WHERE 
        enddate BETWEEN enddate AND '12/31/2020 11:59:59 PM'
)
SELECT * 
FROM tableName
OPTION (maxrecursion 0)

Ожидаемые результаты

Id                  enddate          statusDte      closeId         shceDte                 calcDte             closeEndDte                 parentId          lastClose       lastCloseDte         closeClass  addSe                               town                      code
----------- ----------------------- ------------- ----------- ----------------------- ----------------------- ----------------------- ----------------------- ----------- ----------------------- ----------- --------------------------------- ---------------------- --------------------------------------------------
133           2011-04-04 00:00:00.000 22            14453       NULL                    2011-04-04 00:00:00.000 2099-12-31 00:00:00.000 NULL                    0           NULL                    1           4707 EXECUTIVE DRIVE  ''             SAN DIEGO               123
56           2018-12-07 13:00:00.000 22            52354       NULL                    2018-12-07 13:00:00.000 2019-12-07 00:00:00.000 NULL                    0           NULL                    1           75 STATE ST FL 24  ''                BOSTON                   345
12          2021-02-05 17:00:00.000 22            75751       NULL                    2021-02-05 17:00:00.000 NULL                    NULL                    0           NULL                    1           1450 FRAZEE RD STE 308  ''           SAN DIEGO                 678
334          2019-03-07 16:30:00.000 15            66707       2019-03-07 16:30:00.000 2019-03-23 21:00:00.000 NULL                    NULL                    0           2019-03-07 16:30:00.000 1           42690 RIO NEDO, STE E  ''            TEMECULA                 91011
33          2020-01-10 17:00:00.000 22            65568       NULL                    2020-01-10 17:00:00.000 NULL                    NULL                    0           2018-01-10 17:00:00.000 1           2518 UNICORNIO ST.  ''               CARLSBAD                  136
55          2020-04-16 20:00:00.000 22            67812       NULL                    2020-04-16 20:00:00.000 NULL                    NULL                    0           2018-04-17 20:00:00.000 1           4534 OSPREY STREET  ''               SAN DIEGO                 653
66          2020-02-21 17:00:00.000 22            75956       NULL                    2020-02-21 17:00:00.000 NULL                    NULL                    0           2019-02-21 17:00:00.000 1           3511 CAMINO DEL RIO S, STE 305  ''   SAN DIEGO                 0484
094          2021-02-20 21:00:00.000 22            75629       NULL                    2021-02-20 21:00:00.000 NULL                    NULL                    0           NULL                    1           29349 EAGLE DR  ''                   MURRIETA                 345

Ответы [ 2 ]

1 голос
/ 28 марта 2019

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

Далее, вы (надеюсь) не поняли фактический запрос. Общие названия, такие как «tableA», мешают пониманию.

Далее - ваше первое выражение в регистре кажется очень подозрительным. У вас одна ветка возвращает tb.id, а другие возвращают то, что выглядит как дата (или datetime). К сожалению, вы можете использовать int для datetime. Может не иметь никакого смысла, и это не приведет к ошибке. Итак, имеет ли это смысл?

Далее - вы допустили общую ошибку с границами даты и времени. В зависимости от ваших данных вы никогда не узнаете этого. Но нет никаких оснований ожидать этого, и есть все основания написать свою логику, чтобы избежать какой-либо возможности. Тибор очень подробно обсуждает здесь . Укороченная версия - ваша верхняя граница всегда должна быть эксклюзивной, чтобы поддерживать все возможные значения времени для вашего типа данных. 23:59:59 будет игнорировать любые значения времени с ненулевыми миллисекундами. И используйте буквальный формат, который не зависит от языка или настроек соединения.

Далее вы добавляете путаницу. Вы назвали свои столбцы в объявлении cte, но в вашем коде также есть псевдонимы для некоторых (но не для всех - смотрите, см. Комментарий о согласованности) столбцов, которые значительно отличаются от фактического имени столбца для cte. 2-й столбец для cte - «enddate», запрос привязки использует псевдоним «ForecastDueDate»

Далее, у вас есть это: tb.statusDte = 5. Имя подразумевает дату; буквальное подразумевает что-то другое. У вас есть другие столбцы, которые заканчиваются на «Dte», которые, очевидно, даты, но не этот? Опасность, опасность!

Далее вы ссылаетесь на столбцы «a.closeClass» и «a.statusDate». Нет таблицы или псевдонима с именем "a".

Наконец, у вас есть:

WHERE enddate BETWEEN enddate AND '12/31/2020 11:59:59 PM'

Подумайте о том, что вы написали. Не всегда ли enddate между enddate и 31.12.2010 (если enddate <= это значение)? Я думаю, что это источник вашей проблемы. Вы не вычисляете и не настраиваете что-либо из якоря, поэтому повторяемая часть просто продолжает выбирать, выбирать и выбирать. Нет логики для завершения рекурсии. </p>

Следующий вопрос, очевидно, «сейчас, чтобы это исправить». Это невозможно сказать, не зная вашей схемы, что она представляет и вашей цели. Использование рекурсии здесь не очевидно.

0 голосов
/ 28 марта 2019

Если данные находятся в структуре, в которой иерархия между записями представляет собой цикл, то рекурсия становится бесконечной, вызывая проблему в SQL. Вы увидите, что ресурсы, используемые процессом SQL, значительно увеличиваются. Если вы используете MAXRECURSION с значением, отличным от 0 (ноль позволяет SQL продолжать рекурсию без ограничения), вы сможете ограничить рекурсию. С данными, которые зацикливаются или ссылаются друг на друга, вы можете MAXRECURSION параметр

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...