问题
In my MS SQL 2008 R2 database I have this table:
TABLE [Hierarchy]
[ParentCategoryId] [uniqueidentifier] NULL,
[ChildCategoryId] [uniqueidentifier] NOT NULL
I need to write a query that will generate all paths that lead to a given Node.
Lets say it I have the following tree:
A
-B
--C
-D
--C
Which would be stored as:
NULL | A
A | B
A | D
B | C
D | C
When asking for the Paths for C, I would like to get back two paths (written more or less like this):
A > B > C,
A > D > C
回答1:
Here is my solution, Sql Fiddle
DECLARE @child VARCHAR(10) = 'C'
;WITH children AS
(
SELECT
ParentCategoryId,
CAST(ISNULL(ParentCategoryId + '->' ,'') + ChildCategoryId AS VARCHAR(4000)) AS Path
FROM Hierarchy
WHERE ChildCategoryId = @child
UNION ALL
SELECT
t.ParentCategoryId,
list= CAST(ISNULL(t.ParentCategoryId + '->' ,'') + d.Path AS VARCHAR(4000))
FROM Hierarchy t
INNER JOIN children AS d
ON t.ChildCategoryId = d.ParentCategoryId
)
SELECT Path
from children c
WHERE ParentCategoryId IS NULL
Output:
A->D->C
A->B->C
UPDATE:
@AlexeiMalashkevich, to just get id, you may try this
SQL Fiddle
DECLARE @child VARCHAR(10) = 'C'
;WITH children AS
(
SELECT
ParentCategoryId,
ChildCategoryId AS Path
FROM Hierarchy
WHERE ChildCategoryId = @child
UNION ALL
SELECT
t.ParentCategoryId,
d.ParentCategoryId
FROM Hierarchy t
INNER JOIN children AS d
ON t.ChildCategoryId = d.ParentCategoryId
)
SELECT DISTINCT PATH
from children c
回答2:
Possible solution is to use recursive CTE as mentioned by @a_horse_with_no_name:
CREATE TABLE [Hierarchy](
[ParentCategoryId] CHAR(1) NULL,
[ChildCategoryId] CHAR(1) NOT NULL
);
INSERT INTO Hierarchy
SELECT NULL, 'A' UNION ALL
SELECT 'A', 'B' UNION ALL
SELECT 'A', 'D' UNION ALL
SELECT 'B', 'C' UNION ALL
SELECT 'D', 'C';
WITH CTE AS (
SELECT
ParentCategoryId, ChildCategoryId,
CAST(ISNULL(ParentCategoryId,'') + ChildCategoryId AS VARCHAR(255)) [Path]
FROM Hierarchy
WHERE ParentCategoryId IS NULL
UNION ALL
SELECT
H.ParentCategoryId, H.ChildCategoryId,
CAST(C.[Path] + ' > ' + H.ChildCategoryId AS VARCHAR(255)) [Path]
FROM Hierarchy H
INNER JOIN CTE C ON C.ChildCategoryId = H.ParentCategoryId
) SELECT * FROM CTE;
回答3:
That's an interesting hierarchy structure. Seems to allow for parents to possibly be children of their children. If this were to happen this code logic would break, but as long as that doesn't occur this should work.
Create Function dbo.IdentifyHierarchyPaths (@DeepestChildNode UniqueIdentifier)
Returns @hierarchy Table
(
Hierarchy Varchar(Max)
)
As
Begin
;With BuildHier As
(
Select Convert(Varchar(Max),h2.ChildCategoryId) As child, Convert(Varchar(Max),h1.ChildCategoryId) + ' > ' + Convert(Varchar(Max),h2.ChildCategoryId) As hier
From Hierarchy h1
Left Join Hierarchy h2
On h1.ChildCategoryId = h2.ParentCategoryId
Where h1.ParentCategoryId Is Null
Union All
Select Convert(Varchar(Max),h1.ChildCategoryId) As child, bh.hier + ' > ' + Convert(Varchar(Max),h1.ChildCategoryId) As hier
From BuildHier bh
Join Hierarchy h1
On bh.child = h1.ParentCategoryId
), HierWithTopLevel As
(
Select Convert(Varchar(Max),ChildCategoryId) As hierarchy
From Hierarchy
Where ParentCategoryId Is Null
Union
Select hier
From BuildHier
)
Insert @hierarchy
Select hierarchy
From HierWithTopLevel
Where Right(hierarchy,36) = Convert(Varchar(36),@DeepestChildNode);
Return;
End;
来源:https://stackoverflow.com/questions/14241936/how-can-i-generate-a-hierarchy-path-in-sql-that-leads-to-a-given-node