Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Запрос на обход дерева.  [new]
Oblom
Member

Откуда: Moscow Square
Сообщений: 635
Приветствую!
Есть таблица T с двумя полями ID и Parent_ID типа nvarchar, где Parent_ID ссылается на ID, ID уникален.
Нужно получить для каждой записи в T значение верхнего узла дерева, у которого Parent_ID is null.
На основе MSDN я соорудил вот такое:
WITH DirectReports(ID, Parent_ID, Sort) AS 
(
    SELECT ID, Parent_ID, ID
    FROM T
    WHERE Parent_ID IS NULL
    UNION ALL
    SELECT e.ID, e.Parent_ID, RTRIM(Sort) + '| ' + e.ID
    FROM T e
        INNER JOIN DirectReports d
        ON e.Parent_ID= d.ID
)
SELECT ID, 
CASE WHEN Parent_ID IS NOT NULL THEN SUBSTRING(Sort,1,CHARINDEX('|', Sort)-1) ELSE ID END
FROM DirectReports
ORDER BY Sort
но мне кажется, должны быть варианты и поизящнее.
Может кто сталкивался, задача-то типичная.
15 июн 11, 16:25    [10817222]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на обход дерева.  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
А это вот чего такое: '| '? Тоже в msdn было?
15 июн 11, 16:26    [10817232]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на обход дерева.  [new]
Oblom
Member

Откуда: Moscow Square
Сообщений: 635
Гавриленко Сергей Алексеевич,

Ага:
F. Using a recursive common table expression to display a hierarchical list
The following example builds on Example C by adding the names of the manager and employees, and their respective titles. The hierarchy of managers and employees is additionally emphasized by indenting each level. 

 Copy Code 
USE AdventureWorks;
GO
WITH DirectReports(Name, Title, EmployeeID, EmployeeLevel, Sort)
AS (SELECT CONVERT(varchar(255), c.FirstName + ' ' + c.LastName),
        e.Title,
        e.EmployeeID,
        1,
        CONVERT(varchar(255), c.FirstName + ' ' + c.LastName)
    FROM HumanResources.Employee AS e
    JOIN Person.Contact AS c ON e.ContactID = c.ContactID 
    WHERE e.ManagerID IS NULL
    UNION ALL
    SELECT CONVERT(varchar(255), REPLICATE ('| ' , EmployeeLevel) +
        c.FirstName + ' ' + c.LastName),
        e.Title,
        e.EmployeeID,
        EmployeeLevel + 1,
        CONVERT (varchar(255), RTRIM(Sort) + '| ' + FirstName + ' ' + 
                 LastName)
    FROM HumanResources.Employee as e
    JOIN Person.Contact AS c ON e.ContactID = c.ContactID
    JOIN DirectReports AS d ON e.ManagerID = d.EmployeeID
    )
SELECT EmployeeID, Name, Title, EmployeeLevel
FROM DirectReports 
ORDER BY Sort;
GO

 
15 июн 11, 16:33    [10817293]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на обход дерева.  [new]
Oblom
Member

Откуда: Moscow Square
Сообщений: 635
Oblom,

но спасибо за мысль:
WITH DirectReports(ID, Parent_ID, Sort) AS 
(
    SELECT ID, Parent_ID, ID
    FROM T
    WHERE Parent_ID IS NULL
    UNION ALL
    SELECT e.ID, e.Parent_ID, d.Sort
    FROM T e
        INNER JOIN DirectReports d
        ON e.Parent_ID= d.ID
)
SELECT ID, Sort
FROM DirectReports
ORDER BY Sort
Извините, что отнял время.
15 июн 11, 16:37    [10817342]     Ответить | Цитировать Сообщить модератору
 Re: Запрос на обход дерева.  [new]
smls
Guest
Oblom,

у Вас небольшая неточность, приводящая к неверному результату.
в строке 'SELECT e.ID, e.Parent_ID, d.sort ' должно быть
'SELECT e.ID, e.Parent_ID, d.id ' и в последнем select - distinct.

Как-то вот так :

WITH DirectReports(ID, Parent_ID, Sort) AS
(
SELECT ID, Parent_ID, ID
FROM #T
WHERE Parent_ID IS NULL
UNION ALL
SELECT e.ID, e.Parent_ID, d.id
FROM #T e
INNER JOIN DirectReports d
ON e.Parent_ID= d.ID
)
SELECT distinct ID, Sort
FROM DirectReports
ORDER BY Sort
16 июн 11, 15:34    [10822699]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить