Как вы получаете последнюю запись, сгенерированную в рекурсивном CTE?

StackOverflow https://stackoverflow.com/questions/35320

Вопрос

В приведенном ниже коде я использую рекурсивное CTE (Common Table Expression) в SQL Server 2005, чтобы попытаться найти родительский элемент верхнего уровня базовой иерархической структуры. Правило этой иерархии состоит в том, что у каждого CustID есть ParentID, а если у CustID нет родителя, то ParentID = CustID, и это самый высокий уровень.

DECLARE @LookupID int

--Our test value
SET @LookupID = 1

WITH cteLevelOne (ParentID, CustID) AS
(
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID
        WHERE c.CustID <> a.CustomerID
)

Так что, если tblCustomer выглядит так:

ParentID    CustID
5            5
1            8
5            4
4            1

Результат, полученный из приведенного выше кода:

ParentID    CustID
4            1
5            4
5            5

Я хочу только последнюю строку этого результата:

ParentID    CustID
5            5

Как мне просто вернуть последнюю запись, сгенерированную в CTE (которая будет CustID наивысшего уровня)?

Также обратите внимание, что в этой таблице есть несколько несвязанных иерархий CustID, поэтому я не могу просто выполнить SELECT * FROM tblCustomer WHERE ParentID = CustID. Я не могу заказать по ParentID или CustID, потому что идентификационный номер не связан с тем, где он находится в иерархии.

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

Решение

Если вы просто хотите получить максимальную глубину рекурсии, не могли бы вы сделать что-то подобное? Тогда, когда вы действительно запрашиваете CTE, просто ищите строку с max (Depth)? Вот так:

DECLARE @LookupID int

--Our test value
SET @LookupID = 1;

WITH cteLevelOne (ParentID, CustID, Depth) AS
(
        SELECT   a.ParentID, a.CustID, 1
        FROM     tblCustomer AS a
        WHERE    a.CustID = @LookupID
    UNION ALL
        SELECT   a.ParentID, a.CustID, c.Depth + 1
        FROM     tblCustomer AS a
        INNER JOIN cteLevelOne AS c ON a.CustID = c.ParentID 
        WHERE c.CustID <> a.CustID
)
select * from CTELevelone where Depth = (select max(Depth) from CTELevelone)

или, адаптируя то, что предлагает Тревор, это можно использовать с тем же CTE:

select top 1 * from CTELevelone order by Depth desc

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

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

Я не уверен, что полностью понимаю проблему, но просто взломать & amp; косая черта, вы можете попробовать:

SELECT TOP 1 FROM cteLevelOne ORDER BY CustID DESC

Это предполагает, что CustID также в порядке, как в примере, а не что-то вроде GUID.

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

Msg 530, Уровень 16, Состояние 1, Строка 15 Заявление прекращено. Максимальная рекурсия 100 была исчерпана до завершения оператора.

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