问题
I want to get the path for each department with this format 1.1, 1.2 and so on. This is my department table :
id name parentId
--------------------
1 Dep 1 0
2 Dep 2 1
3 Dep 3 0
4 Dep 4 1
5 Dep 5 4
6 Dep 6 2
This is my recursive CTE that give me the parents and children in a flat table starting from a root department.
WITH recursiveCte (parentId, id, name, Level)
AS
(
-- Anchor member definition
SELECT
d.parentId, d.id, d.name,
0 AS Level
FROM
Department AS d
WHERE
parentId = 0
UNION ALL
-- Recursive member definition
SELECT
d.parentId, d.id, d.name,
Level + 1
FROM
Department AS d
INNER JOIN
recursiveCte AS r ON d.parentId = r.id
)
-- Statement that executes the CTE
SELECT parentId,id, name, Level
FROM recursiveCte
ORDER BY id
Current results:
parentId id name Level
-------------------------------
0 1 Dep 1 0
1 2 Dep 2 1
0 3 Dep 3 0
1 4 Dep 4 1
4 5 Dep 5 2
2 6 Dep 6 2
Desired results:
parentId id name Level Path
--------------------------------------
0 1 Dep 1 0 1
1 2 Dep 2 1 1.1
2 6 Dep 6 2 1.1.1
1 4 Dep 4 1 1.2
4 5 Dep 5 2 1.2.1
0 3 Dep 3 0 2
Thanks.
回答1:
Here is a working solution. It is difficult to describe in words why this works, so I recommend taking apart the query to see how it works yourself. Basically, we recursively build the path string you want to see, using ROW_NUMBER
to keep track to which particular parent each new path addition belongs.
recursiveCte (parentId, id, name, Level, Path, FullPath) AS (
SELECT d.parentId, d.id, d.name, 0 AS Level,
CAST(ROW_NUMBER() OVER (ORDER BY d.id) AS nvarchar(max)),
RIGHT('000' + CAST(ROW_NUMBER() OVER (ORDER BY d.id) AS nvarchar(max)), 3)
FROM Department AS d
WHERE parentId = 0
UNION ALL
SELECT d.parentId, d.id, d.name, r.Level + 1,
r.Path + '.' +
CAST(ROW_NUMBER() OVER (PARTITION BY r.Level ORDER BY d.id) AS nvarchar(max)),
r.FullPath + '.' + RIGHT('000' + CAST(ROW_NUMBER() OVER
(PARTITION BY r.Level ORDER BY d.id) AS nvarchar(max)), 3)
FROM Department AS d
INNER JOIN recursiveCte AS r
ON d.parentId = r.id
)
SELECT parentId, id, name, Level, Path, FullPath
FROM recursiveCte
ORDER BY FullPath;
Demo
Edit:
I slightly edited my original answer so that it now sorts the path string using a fixed-width version, i.e. every number has a fixed width of 3 digits. This means that 001
will always sort before 010
, which is the behavior we want.
来源:https://stackoverflow.com/questions/50893656/sql-server-get-path-with-recursive-cte