Как вы получаете последнюю запись, сгенерированную в рекурсивном CTE?
-
09-06-2019 - |
Вопрос
В приведенном ниже коде я использую рекурсивное 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 была исчерпана до завершения оператора.