问题
I need a SQL query giving me the complete tree path of one item. The tables Looks like this and there is a 1:n relation between MyItem_MyItemId and MyItemMapping_MyItemId.
Table MyItem:
MyItem_MyItemId | MyItem_Title
1 | Desktop
2 | Workspace
3 | Folder1
4 | Folder2
5 | Folder3
6 | Folder4
...
Table MyItemMapping:
MyItemMapping_MyItemId | MyItemMapping_MyItemParentId
4 | 3
3 | 2
2 | 1
1 | NULL
5 | 2
6 | 2
...
Now I Need a query the brings the path for the Folder2 like "Desktop\Workspace\Folder1\Folder2.
I tried it with a Recursive Query (see below) but SQL Server Needs about 10 seconds to resolve it. I have only 5000 records in database. I could figure out that with this query, the path is calculated for all 5000 records but I Need it only of one item. Can anybody help me?
WITH
MyTable as
(
select MyItem_MyItemId, MyItem_Title, MyItemMapping_MyItemParentId
from MyItem inner join MyItemMapping on MyItem_MyItemId = MyItemMapping_MyItemId
),
RecursiveTable AS
(
select t.MyItem_MyItemId, t.MyItem_Title, t.MyItemMapping_MyItemParentId
from MyTable as t
Where MyItemMapping_MyItemParentId is null
union all
select t.MyItem_MyItemId, CAST(RecursiveTable.MyItem_Title + '\' + t.MyItem_Title AS NVARCHAR(max)), t.MyItemMapping_MyItemParentId
from MyTable as t
JOIN RecursiveTable ON RecursiveTable.MyItem_MyItemId = t.MyItemMapping_MyItemParentId
)
select MyItem_Title from RecursiveTable where MyItem_MyItemid = 4
Thank you vey much.
Best regards. Marc
回答1:
Move in the opposite direction. After selected is necessary items, use pattern with FOR XML clause for creating a list of backslash delimited valid values.
DECLARE @MyItemMapping_MyItemId int = 4
;WITH cte AS
(
SELECT MyItemMapping_MyItemId, MyItemMapping_MyItemParentId, 1 AS rn
FROM MyItemMapping
Where MyItemMapping_MyItemId = @MyItemMapping_MyItemId
UNION ALL
SELECT m.MyItemMapping_MyItemId, m.MyItemMapping_MyItemParentId, rn + 1
FROM MyItemMapping m JOIN cte c ON c.MyItemMapping_MyItemParentId = m.MyItemMapping_MyItemId
)
SELECT STUFF((SELECT '/' + m.MyItem_Title
FROM cte c JOIN MyItem m
ON c.MyItemMapping_MyItemId = m.MyItem_MyItemId
ORDER BY c.rn DESC
FOR XML PATH, TYPE).value('.[1]', 'nvarchar(max)'), 1, 1, '') AS pathFolder
pathFolder
Result:
PathFolder
Desktop/Workspace/Folder1/Folder2
Demo on SQLFiddle
回答2:
Please check the query:
declare @MyItem as table (MyItem_MyItemId INT, MyItem_Title nvarchar(50))
insert into @MyItem values
(1, 'Desktop'),
(2, 'Workspace'),
(3, 'Folder1'),
(4, 'Folder2')
declare @MyItemMapping as table (MyItemMapping_MyItemId INT, MyItemMapping_MyItemParentId int)
insert into @MyItemMapping values
(4, 3),
(3, 2),
(2, 1),
(1, NULL)
select * From @MyItem
select * From @MyItemMapping
;WITH parent AS
(
SELECT MyItemMapping_MyItemId, MyItemMapping_MyItemParentId, CAST( b.MyItem_Title as nvarchar(max))MyItem_Title
from @MyItemMapping a INNER JOIN @MyItem b on a.MyItemMapping_MyItemId=b.MyItem_MyItemId
WHERE MyItemMapping_MyItemParentId is NULL
UNION ALL
SELECT t.MyItemMapping_MyItemId, t.MyItemMapping_MyItemParentId ,CAST( parent.MyItem_Title+'/'+ b.MyItem_Title as nvarchar(max))MyItem_Title
FROM parent INNER JOIN @MyItemMapping t ON parent.MyItemMapping_MyItemId = t.MyItemMapping_MyItemParentId
INNER JOIN @MyItem b on t.MyItemMapping_MyItemId=b.MyItem_MyItemId
)
SELECT MyItem_Title FROM parent where MyItemMapping_MyItemId=(select MAX(MyItem_MyItemId) from @MyItem)
OR
declare @output varchar(max)
;WITH parent AS
(
SELECT MyItemMapping_MyItemId, MyItemMapping_MyItemParentId
from @MyItemMapping
WHERE MyItemMapping_MyItemParentId is NULL
UNION ALL
SELECT t.MyItemMapping_MyItemId, t.MyItemMapping_MyItemParentId
FROM parent INNER JOIN @MyItemMapping t ON parent.MyItemMapping_MyItemId = t.MyItemMapping_MyItemParentId
)
SELECT @output = COALESCE(@output + '/', '')+ (select MyItem_Title from @MyItem where MyItem_MyItemId=MyItemMapping_MyItemId)
FROM parent where MyItemMapping_MyItemId <= 4 group by MyItemMapping_MyItemId order by MyItemMapping_MyItemId
select @output
来源:https://stackoverflow.com/questions/15585155/sql-server-query-for-tree-path-of-one-item