Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/79.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
T-SQL排序递归查询-父/子结构_Sql_Tsql_Recursion_Hierarchy - Fatal编程技术网

T-SQL排序递归查询-父/子结构

T-SQL排序递归查询-父/子结构,sql,tsql,recursion,hierarchy,Sql,Tsql,Recursion,Hierarchy,我正在尝试(但失败)正确排序递归CTE。我的表由一个父子结构组成,其中一个任务可以在不同的级别上与另一个任务关联 例如,我可以创建一个任务(这是父任务),然后从该任务创建一个子任务,然后从该子任务创建一个子任务,依此类推 下面是我包含的一些测试数据。目前它是按Path按字母顺序排列的 所以如果我要创建一个任务。它会给我一个该任务的TaskID(比如50)——然后我可以为该主任务创建5个子任务(51,52,53,54,55)。然后,我可以将子任务添加到5个子任务(51->56)(53->57)中

我正在尝试(但失败)正确排序递归CTE。我的表由一个父子结构组成,其中一个任务可以在不同的级别上与另一个任务关联

例如,我可以创建一个任务(这是父任务),然后从该任务创建一个子任务,然后从该子任务创建一个子任务,依此类推

下面是我包含的一些测试数据。目前它是按
Path
按字母顺序排列的

所以如果我要创建一个任务。它会给我一个该任务的TaskID(比如50)——然后我可以为该主任务创建5个子任务(51,52,53,54,55)。然后,我可以将子任务添加到5个子任务(51->56)(53->57)中,但当我想要订单时,我需要它返回

所以我需要它的顺序

  • 五十
    • 五十一
      • 56
    • 五十二
    • 五十三
      • 57
    • 54
    • 五十五
测试数据的正确顺序

这是我一直在使用的代码

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]
我有一种感觉,这将是显而易见的,但我真的不知道如何继续。我考虑了更多的递归、函数和拆分字符串,但没有成功


如果我说得不清楚,请道歉这很简单。你不需要使用任何循环或函数。我假设您已经导出了路径值。基于此,我导出了解决方案。 选择C.TASKID,复制(“”,(LEN([PATH])-LEN(REPLACE([PATH],‘,’,“”))+2))+CONVERT(NVARCHAR(20),C.TASKID),[PATH] 来自CTE C 按[路径]排序


最简单的方法是将按键固定长度。e、 g.
038007
将在
038012
之前订购,但对于最大的taskid,填充长度必须是安全的。尽管您可以保持
路径的可读性,并创建额外的填充字段进行排序

更安全的版本是这样做,但是从行号创建一个填充路径。其中,填充大小必须足够大,以支持最大数量的子项

SELECT C.TASKID, REPLICATE(' ', (LEN([PATH]) - LEN(REPLACE([PATH],',','')) + 2) ) + CONVERT(NVARCHAR(20),C.TASKID), [PATH] FROM CTE C ORDER BY [PATH]

您可能会比固定的子项长度更花哨,确定子项的数量并根据所述长度确定填充。或者使用基于同级数量的编号行并反向遍历(可能只是说出一些未经测试的想法),但使用简单的有序路径就足够了。

如果最顶端的CTE(如下面的查询)是您的表结构,那么下面的代码可能就是解决方案。 以CTE为例 ( 选择7112 TASKID,NULL PARENTID UNION ALL 选择7120 TASKID,7112 ParanetID UNION ALL 选择7139 TASKID,7112 ParanetID UNION ALL 选择7150 TASKID,7112 ParanetID UNION ALL 选择23682 TASKID,7112 ParanetID UNION ALL 选择7100 TASKID,7112 ParanetID UNION ALL 选择23691 TASKID,7112 ParanetID UNION ALL 选择23696 TASKID,7112 ParanetID UNION ALL 选择23700 TASKID,23696 ParanetID UNION ALL 选择23694 TASKID,23691 ParanetID UNION ALL 选择23689 TASKID,7120 ParanetID UNION ALL 选择7148 TASKID,23696 ParanetID UNION ALL 选择7126 TASKID,7120 ParanetID UNION ALL 选择7094 TASKID,7120 ParanetID UNION ALL 选择7098 TASKID,7094 ParanetID UNION ALL 选择23687 TASKID,7094 ParanetID

) ,递归为 ( 选择TASKID,CONVERT(NVARCHAR(MAX),CONVERT(NVARCHAR(20),TASKID))[PATH] 来自CTE 其中PARENTID为NULL

联合所有

选择C.TASKID,CONVERT(NVARCHAR(MAX),CONVERT(NVARCHAR(20),R.[PATH])+','+CONVERT(NVARCHAR(20),C.TASKID)) 从递归 R.TASKID=C.PARENTID上的内部联接CTE C )

选择C.TASKID,复制(“”,(LEN([PATH])-LEN(REPLACE([PATH],‘,’,“”))+2))+'.+CONVERT(NVARCHAR(20),C.TASKID) 从递归C 按[路径]排序
尝试在SSMS中以文本输出模式执行此查询。因此,您可以看到差异

如果我错了,请纠正我,但您似乎试图模拟OP发布的显示值树。然而,这棵树仅仅是为了展示预期的顺序。您的代码似乎无助于排序OP的数据。太棒了。我为此奋斗了3个小时。我现在可以吻你了!哈哈
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
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

) ,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]