我在表单中使用树控件,它使用列ID,ParentID,ReasonText。 例如:
ID ParentID ReasonText
1 0 Level1A
2 0 Level1B
3 1 Level2AA
4 1 Level2AB
5 2 Level2BA
6 4 Level3ABA
我想从SQL获取结构,这样如果我选择ID = 6,例如我想返回“Level1A> Level2AB> Level3ABA”,1将返回“Level1A”。 我有一个复杂的SQL语句,可以达到4级。
DECLARE @ipid int = 45
DECLARE @pathdelimiter varchar = '>'
SELECT
R1.ID, N'' +
CASE WHEN (SELECT R4.ReasonText FROM CLG_CallReasonTree R4 WHERE R4.ID = (SELECT R3.ParentID FROM CLG_CallReasonTree R3 WHERE R3.ID = (SELECT R2.ParentID FROM CLG_CallReasonTree R2 WHERE R2.ID = R1.ParentID))) IS NOT NULL
THEN (SELECT R4.ReasonText FROM CLG_CallReasonTree R4 WHERE R4.ID = (SELECT R3.ParentID FROM CLG_CallReasonTree R3 WHERE R3.ID = (SELECT R2.ParentID FROM CLG_CallReasonTree R2 WHERE R2.ID = R1.ParentID))) + @pathdelimiter ELSE '' END +
CASE WHEN (SELECT R3.ReasonText FROM CLG_CallReasonTree R3 WHERE R3.ID = (SELECT R2.ParentID FROM CLG_CallReasonTree R2 WHERE R2.ID = R1.ParentID)) IS NOT NULL
THEN (SELECT R3.ReasonText FROM CLG_CallReasonTree R3 WHERE R3.ID = (SELECT R2.ParentID FROM CLG_CallReasonTree R2 WHERE R2.ID = R1.ParentID)) + @pathdelimiter ELSE '' END +
CASE WHEN (SELECT R2.ReasonText FROM CLG_CallReasonTree R2 WHERE R2.ID = R1.ParentID) IS NOT NULL
THEN (SELECT R2.ReasonText FROM CLG_CallReasonTree R2 WHERE R2.ID = R1.ParentID) + @pathdelimiter ELSE '' END +
R1.ReasonText AS TreePath
FROM CLG_CallReasonTree R1
WHERE R1.ID = @ipid
我确信必须有一种方法可以更简单地使用递归,但无法管理它。
答案 0 :(得分:2)
declare @CLG_CallReasonTree table
(
ID int,
ParentID int,
ReasonText varchar(100)
)
insert into @CLG_CallReasonTree(ID, ParentID, ReasonText)
values
(1, 0, 'Level1A'),
(2, 0, 'Level1B'),
(3, 1, 'Level2AA'),
(4, 1, 'Level2AB'),
(5, 2, 'Level2BA'),
(6, 4, 'Level3ABA')
declare @ID int = 6
/* for single id with for_xml */
;with cteTree as
(
select t.ID, t.ParentID, t.ReasonText, 1 as lvl
from @CLG_CallReasonTree t
where t.ID = @ID
union all
select tt.ID, tt.ParentID, tt.ReasonText, t.lvl+1
from cteTree t
inner join @CLG_CallReasonTree tt on tt.ID = t.ParentID
)
select stuff(
(
select '->' + t.ReasonText
from cteTree t
order by t.lvl desc
for xml path(''), type
).value('.', 'varchar(max)'), 1, 2, '')
/* with reversed path - provides ability to apply like filter */
;with cteTree as
(
select t.ID, t.ParentID, t.ReasonText, 1 as lvl, cast('/' + cast(t.ID as varchar(10)) + '/' as varchar(1000)) as tree_path
from @CLG_CallReasonTree t
where t.ParentID = 0
union all
select tt.ID, tt.ParentID, tt.ReasonText, t.lvl+1, cast('/' + cast(tt.ID as varchar(10)) + t.tree_path as varchar(1000))
from cteTree t
inner join @CLG_CallReasonTree tt on tt.ParentID = t.ID
)
select *
from cteTree
/* path-like ReasonText */
declare @reftable table
(
ID int,
ReasonID int,
Title varchar(100)
)
insert into @reftable(ID, ReasonID, Title)
values
(1, 3, 'AAA'),
(2, 5, 'BBB'),
(3, 0, 'CCC'),
(4, 1, 'DDD'),
(5, 6, 'FFF')
;with cteTree as
(
select t.ID, t.ParentID, cast(t.ReasonText as varchar(1000)) as ReasonText
from @CLG_CallReasonTree t
where t.ParentID = 0
union all
select tt.ID, tt.ParentID, cast(t.ReasonText + '->' + tt.ReasonText as varchar(1000))
from cteTree t
inner join @CLG_CallReasonTree tt on tt.ParentID = t.ID
)
select rt.ID, rt.Title, t.ReasonText
from @reftable rt
inner join cteTree t on t.ID = rt.ReasonID
答案 1 :(得分:1)
您正在寻找的是下面表格的递归CTE。简单的总结是查询重复,直到它达到锚定义中设置的限制。有关其工作原理的详细信息,请参阅Recursive Queries Using Common Table Expressions。
;WITH CallReasonTree (ID, ParentID, ReasonText, TreePath)
AS
(
-- Anchor member definition
SELECT ChildReason.ID, ChildReason.ParentID, ChildReason.ReasonText,
CONVERT(nvarchar(MAX), ChildReason.ReasonText) AS TreePath
FROM CLG_CallReasonTree AS ChildReason
WHERE ChildReason.ParentID = 0
UNION ALL
-- Recursive member definition
SELECT ChildReason.ID, ChildReason.ParentID, ChildReason.ReasonText,
TreePath + '>' + ChildReason.ReasonText AS TreePath
FROM CLG_CallReasonTree AS ChildReason
INNER JOIN CallReasonTree AS ParentReason ON ChildReason.ParentID = ParentReason.ID
)
-- Statement that executes the CTE
SELECT ID, ParentID, ReasonText, TreePath
FROM CallReasonTree
ORDER BY ID
这是结果输出:
ID ParentID ReasonText TreePath
1 0 Level1A Level1A
2 0 Level1B Level1B
3 1 Level2AA Level1A>Level2AA
4 1 Level2AB Level1A>Level2AB
5 2 Level2BA Level1B>Level2BA
6 4 Level3ABA Level1A>Level2AB>Level3ABA