2015-07-20 5 views
2

У меня есть 2 таблицы, сначала содержит данные документов, а вторая - для каталогов.SQL Server CTE - рекурсия

Таблица 1

DocID DirID Name Order 
----- ----- ---- ----- 
1  4  Doc1 2 
2  1  Doc2 1 
3  5  Doc3 1 
4  3  Doc4 1 
5  4  Doc5 1 

Таблица 2

DirID ParentID Name 
----- -------- ---- 
1  NULL  root 
2  1   Dir1 
3  2   Dir2 
4  1   Dir3 
5  3   Dir4 

Структура

root 
-Dir1 
-Dir2 
    -Dir4 
    -Doc3 
    -Doc4 
-Dir3 
-Doc5 
-Doc1 
-Doc2 

Я пытаюсь создать КТР в T-SQL, который будет генерировать этот результат, но я не может понять, как это сделать. Может ли кто-нибудь предложить решение?

Doc2 
Dir3/Doc5 
Dir3/Doc1 
Dir1/Dir2/Doc4 
Dir1/Dir2/Dir4/Doc3 

Root не отображается, документы сортируются по Order в его каталоге и результат сортируются с низкой глубины заказанной по имени полного пути.

+4

показать вам, запрос, что ты пробовал? – Fabio

+0

Примечание. Имя столбца 'order' - это [зарезервированное слово] (https://msdn.microsoft.com/en-us/library/ms189822.aspx), с синтаксисом – xQbert

+0

. Я считаю, что ваш вывод неверен для ** Doc4 ** : 'Dir1/Dir2/Doc4'. Это должно быть 'Dir1/Doc4' за каждую логику. – FutbolFan

ответ

2

Использование CTE для создания иерархии папок
Затем соединить документы в папки
И результат того, с использованием созданных Path для этой цели

DECLARE @Separator AS VARCHAR(1) = '\\' 
--Generating folder hierarchy 
;WITH Info AS 
(
    SELECT f.DirID 
    , f.ParentID 
    , f.Name 
    , CAST(f.Name AS VARCHAR(255)) AS PathValue 
    FROM Folders f 
    WHERE f.ParentID IS NULL 

    UNION ALL 

    SELECT f.DirID 
    , f.ParentID 
    , f.Name 
    , CAST(i.PathValue + @Separator + f.Name AS VARCHAR(255)) 
    FROM Folders f 
    INNER JOIN Info i ON f.ParentID = i.DirID 
) 

-- Join documents to the folder hirarchy 
SELECT i.ParentID 
, i.DirID 
, i.Name 
, d.DocID 
, d.Name 
, i.PathValue + @Separator + CAST(d.OrderNum AS VARCHAR(255)) + '.' + d.Name AS OrderPath 
, i.PathValue + @Separator + d.Name AS DocumentPath 
FROM Info i 
INNER JOIN Documents d ON d.DirID = i.DirID 

UNION ALL 

-- Adding NULL row for folder, will show folder in the result even no documents 
-- This can be removed if you want show only folders which containing documents 
SELECT i.ParentID 
, i.DirID 
, i.Name 
, NULL 
, NULL 
, i.PathValue AS OrderPath 
, i.PathValue AS DocumentPath 
FROM Info i 
ORDER BY OrderPath 

SQL Fiddle

2

Используя Recursive CTE, вы можете легко создать путь, как показано выше:

ПРИМЕЧАНИЕ: Я считаю, что ваш вывод является неправильным для Doc4: Dir1/Dir2/Doc4. Он должен быть Dir1/Doc4 за каждую логику.

;WITH q1 
AS (
    SELECT a.DocID 
     ,b.* 
     ,a.NAME AS rootname 
    FROM tableb b 
    LEFT JOIN tablea a ON b.DirID = a.DirID 
    ) 
,q2 
AS (
    -- anchor 
    SELECT DocID 
     ,DirID 
     ,q1.rootname 
     ,ParentID 
     ,CAST((q1.NAME) AS VARCHAR(1000)) [Path] 
    FROM q1 
    WHERE ParentId IS NULL 

    UNION ALL 

    --recursive member 
    SELECT t.DocID 
     ,t.DirID 
     ,t.rootname 
     ,t.ParentID 
     ,CAST((a.path + '/' + t.NAME) AS VARCHAR(1000)) [Path] 
    FROM q1 AS t 
    INNER JOIN q2 AS a ON t.ParentId = a.DirID 
    ) 
SELECT replace([Path] + '/' + q2.rootname, 'root/', '') AS FinalPath 
FROM q2 
WHERE q2.rootname IS NOT NULL 
ORDER BY FinalPath DESC 

SQL Fiddle Demo

+0

@Triber Что-то не так с этим ответом? – FutbolFan

+0

Извините за поздний ответ, я просто просмотрел некоторые старые вопросы, и я пропустил это. Если я хорошо помню, второй ответ длиннее, но мне это стало понятнее, но оба они работают. – Triber

Смежные вопросы