Как обнаружить циклическую ссылку в запросе SQL Server - SQL Server 2017 - PullRequest
1 голос
/ 24 сентября 2019

У меня есть рекурсивный запрос WITH в SQL Server 2017:

;WITH rec AS (
    SELECT
       col1 AS root_order
      ,col1
      ,col2
      ,col3
      ,col4
      ,col5
      ,col6
      ,col7
      ,col8
      ,col9

    FROM
        TableA


    UNION ALL

    SELECT
        rec.root_order,
        TableA.col2,
        TableA.col3,
        TableA.col4,
        TableA.col5,
        TableA.col6,
        TableA.col7,
        TableA.col8,
        TableA.col9,
        rec.the_level

    FROM
        rec
            INNER JOIN TableA on rec.Details = TableA.Orders
    )

    SELECT DISTINCT * FROM rec

Это приводит к ошибке: The statement terminated. The maximum recursion 100 has been exhausted before statement completion..

Я попытался: OPTION (maxrecursion 0), чтобы разрешить егоПродолжить.Но когда я это делаю, запрос бесконечно зацикливается, так что это не работает.

В Oracle я могу использовать CONNECT BY ROOT и CONNECT BY PRIOR и NOCYCLE, но я знаю такие вещи, которые не так 'Доступно в SQL Server.Итак, я нашел эту ссылку MSDN , которая предлагает что-то вроде:

with hierarchy
as
(
select
    child, 
    parent, 
    0 as cycle,
    CAST('.' as varchar(max)) + LTRIM(child) + '.' as [path]
from
    #hier
where
    parent is null

union all

select
    c.child,
    c.parent,
    case when p.[path] like  '%.' + LTRIM(c.child) + '.%' then 1 else 0 end as cycle,
    p.[path] + LTRIM(c.child) + '.' as [path]
from
    hierarchy as p
    inner join
    #hier as c
    on p.child = c.parent
    and p.cycle = 0
)
select
    child,
    parent,
    [path]
from
    hierarchy
where
    cycle = 1;
go

Для нахождения циклов (или их избежания).Я не могу взять свой текущий запрос и отредактировать его таким образом.Как я могу отредактировать мой текущий SQL-код для выполнения обнаружения циклических ссылок, как в статье MSDN?

Некоторые примеры данных, запрошенные здесь, в SQL FIDDLE .

1 Ответ

0 голосов
/ 25 сентября 2019

То, что я обычно делаю, довольно просто.В запросе привязки (первая часть CTE) я включаю значение «1 AS Level» в список выбора.Затем в нижнем запросе я выбираю Уровень + 1 в качестве Уровня, чтобы я знал, до какой глубины я дошел.Затем я могу просто вставить в нижний запрос предложение здравомыслия, чтобы ограничить глубину, т.е. ГДЕ УРОВЕНЬ <= 10 или любую другую глубину, которую вы хотите.Но да, вам все равно нужно установить MAXRECURSION в 0, если вы хотите подняться выше 100 уровней. </p>

Вот пример, основанный на AdventureWorks:

WITH Materials (BillOfMaterialsID, ProductName, ProductAssemblyID, ComponentID, [Level])
AS
(
    SELECT bom.BillOfMaterialsID, 
           p.[Name], 
           bom.ProductAssemblyID, 
           bom.ComponentID, 
           1
    FROM Production.BillOfMaterials AS bom
    INNER JOIN Production.Product AS p
    ON bom.ComponentID = p.ProductID 
    AND bom.EndDate IS NULL
    WHERE bom.ProductAssemblyID IS NULL

    UNION ALL

    SELECT bom.BillOfMaterialsID, 
           p.[Name], 
           bom.ProductAssemblyID, 
           bom.ComponentID, 
           m.[Level] + 1
    FROM Production.BillOfMaterials AS bom
    INNER JOIN Production.Product AS p
    ON bom.ComponentID = p.ProductID 
    INNER JOIN Materials AS m
    ON bom.ProductAssemblyID = BOM.ComponentID 
    WHERE m.[Level] <= 5
)
SELECT m.BillOfMaterialsID, 
       m.ProductName, 
       m.ProductAssemblyID, 
       m.ComponentID, 
       m.[Level]
FROM Materials AS m
ORDER BY m.[Level], m.BillOfMaterialsID;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...