我正在尝试(并且失败)正确地命令我的递归CTE。我的表由一个父子结构组成,其中一个任务可以在不同的层次上与另一个任务相关联。
例如,我可以创建一个任务(这是父项),然后从中创建一个子任务,然后从该子任务创建一个子任务,依此类推......
以下是我所包含的一些测试数据。目前由Path
订购,按字母顺序排序。
所以,如果我要创建一个任务。它会给我一个任务ID(Say 50) - 然后我可以为该主要任务创建5个子任务(51,52,53,54,55)。然后我可以将子任务添加到5个子任务(51-> 56)(53-> 57)但是当我想要订单时我需要它返回
所以我要求它的顺序
测试数据的正确顺序
以下是我一直在使用的代码
DECLARE @TaskID NUMERIC(10,0)
SET @TaskID = 38
;WITH cte AS
(
SELECT
t.TaskID
,t.ParentID
,t.Title
,CONVERT(VARCHAR(MAX),'') AS [Nest]
,CONVERT(VARCHAR(MAX),'') AS [Path]
,t.CreatedDate
FROM
tasks.Tasks t
WHERE
t.ParentID IS NULL
AND t.TaskID = @TaskID
UNION ALL
SELECT
sub.TaskID
,sub.ParentID
,sub.Title
,cte.[Nest] + CONVERT(VARCHAR(MAX),sub.TaskID) AS [Nest]
,cte.[Path] + ',' + CONVERT(VARCHAR(MAX),sub.TaskID) AS [Path]
,sub.CreatedDate
FROM
tasks.Tasks sub
INNER JOIN cte ON cte.TaskID = sub.ParentID
)
SELECT
TaskID
,ParentID
,Title
,Nest
,[Path]
,CreatedDate
FROM (
SELECT
cte.TaskID
,cte.ParentID
,cte.Title
,NULLIF(LEN(cte.[Path]) - LEN(REPLACE(cte.[Path], ',', '')),0) Nest
,CONVERT(VARCHAR(25),@TaskID) + cte.[Path] AS [Path]
,cte.CreatedDate
FROM
cte
)a
ORDER BY
a.[Path]
我有一种感觉会很明显,但我真的不知道如何继续。我想到了更多的递归,函数,拆分字符串没有成功。
如果我不清楚,请道歉
答案 0 :(得分:1)
最简单的方法是将键填充到固定长度。例如038,007
将在038,012
之前订购。但填充长度必须对最大的taskid是安全的。虽然您可以保留path
以便于阅读,并为分类创建额外的填充字段。
更安全的版本是做同样的事情,但是从row_numbers创建一个填充路径。填充大小必须足够大才能支持最大子项数。
DECLARE @TaskID NUMERIC(10,0)
SET @TaskID = 38
declare @maxsubchars int = 3 --not more than 999 sub items
;with cte as
(
SELECT
t.TaskID
,t.ParentID
,t.Title
,0 AS [Nest]
,CONVERT(VARCHAR(MAX),t.taskid) AS [Path]
,CONVERT(VARCHAR(MAX),'') OrderPath
,t.CreatedDate
FROM
tasks.Tasks t
WHERE
t.ParentID IS NULL
AND t.TaskID = @TaskID
union all
SELECT
sub.TaskID
,sub.ParentID
,sub.Title
,cte.Nest + 1
,cte.[Path] + ',' + CONVERT(VARCHAR(MAX),sub.TaskID)
,cte.OrderPath + ',' + right(REPLICATE('0', @maxsubchars) + CONVERT(VARCHAR,ROW_NUMBER() over (order by sub.TaskID)), @maxsubchars)
,sub.CreatedDate
FROM
tasks.Tasks sub
INNER JOIN cte ON cte.TaskID = sub.ParentID
)
select taskid, parentid, title,nullif(nest,0) Nest,Path, createddate from cte order by OrderPath
你可能比固定的子项长度更加花哨,确定子项的数量并将填充基于所述长度。或者使用基于兄弟姐妹数量的编号行并反向遍历并且可能(只是喷出一些未经测试的想法),但使用简单的有序路径就足够了。
答案 1 :(得分:1)
如果最顶层的CTE(如下面的查询中)是您的表结构,那么下面的代码可能是解决方案。
WITH CTE AS ( SELECT 7112 TASKID ,NULL PARENTID UNION ALL SELECT 7120 TASKID ,7112 ParanetID UNION ALL SELECT 7139 TASKID ,7112 ParanetID UNION ALL SELECT 7150 TASKID ,7112 ParanetID UNION ALL SELECT 23682 TASKID ,7112 ParanetID UNION ALL SELECT 7100 TASKID ,7112 ParanetID UNION ALL SELECT 23691 TASKID ,7112 ParanetID UNION ALL SELECT 23696 TASKID ,7112 ParanetID UNION ALL SELECT 23700 TASKID ,23696 ParanetID UNION ALL SELECT 23694 TASKID ,23691 ParanetID UNION ALL SELECT 23689 TASKID ,7120 ParanetID UNION ALL SELECT 7148 TASKID ,23696 ParanetID UNION ALL SELECT 7126 TASKID ,7120 ParanetID UNION ALL SELECT 7094 TASKID ,7120 ParanetID UNION ALL SELECT 7098 TASKID ,7094 ParanetID UNION ALL SELECT 23687 TASKID ,7094 ParanetID在SSMS中以文本输出模式尝试此查询。这样你就可以看到差异) ,RECURSIVECTE AS ( SELECT TASKID, CONVERT(NVARCHAR(MAX),convert(nvarchar(20),TASKID)) [PATH] FROM CTE WHERE PARENTID IS NULL
UNION ALL
SELECT C.TASKID, CONVERT(NVARCHAR(MAX),convert(nvarchar(20),R.[PATH]) + ',' + convert(nvarchar(20),C.TASKID)) FROM RECURSIVECTE R INNER JOIN CTE C ON R.TASKID = C.PARENTID )
SELECT C.TASKID, REPLICATE(' ', (LEN([PATH]) - LEN(REPLACE([PATH],',','')) + 2) ) + '.' + CONVERT(NVARCHAR(20),C.TASKID) FROM RECURSIVECTE C ORDER BY [PATH]
答案 2 :(得分:0)
很简单。 Yuu不需要使用任何循环或函数。我假设你已经导出了PATH值。基于此我推导出了解决方案。
SELECT C.TASKID, REPLICATE(' ', (LEN([PATH]) - LEN(REPLACE([PATH],',','')) + 2) ) + CONVERT(NVARCHAR(20),C.TASKID), [PATH] FROM CTE C ORDER BY [PATH]