SQL中的递归挑战

时间:2014-02-27 17:06:34

标签: sql-server

我有两张桌子。

一个列出了大约60个带有id的根文件夹,在本例中为“docnumber”。

另一个表中有大约260万行由文件夹组成 并且每个文件的ID都是“docnumber”。每行的类型为F或D,具体取决于它是文档还是文件夹。

根表

docnumber,name

100,测试

200,anothertest

文件夹/文件表

type,parentnumber,docnumber,name

D,500,600,testdoc

F,300,500,testfolder

F,200,300,testsubfolder

如何在文件夹/文档表中浏览D类的每一行,并添加一个名为TopLevelFolder的字段,该字段将从该根文档中选择该文档的顶级文件夹?它需要通过所有文件夹级别才能从根表中找到顶级文件夹。

非常感谢!

1 个答案:

答案 0 :(得分:1)

基本上,您只需要一个递归CTE来组装层次结构树,并且需要一个排名函数来标记顶层。

;WITH Hierarchy AS(
    SELECT ParentNumber, DocNumber, 1 Tier 
    FROM FolderDocument 
    WHERE [Type] = 'D'
    UNION ALL
    SELECT fd.ParentNumber, h.DocNumber, h.Tier + 1
    FROM FolderDocument fd
    INNER JOIN Hierarchy h
    ON fd.DocNumber = h.ParentNumber
    WHERE fd.ParentNumber IS NOT NULL
)
,HierarchyRank AS(
    SELECT *, RANK() OVER (
        PARTITION BY h.DocNumber ORDER BY h.Tier DESC) RankNum
    FROM Hierarchy h
)
SELECT hr.DocNumber, hr.ParentNumber AS TopFolderNumber, fdd.Name AS DocName, fdf.Name AS TopFolderName
FROM HierarchyRank hr
LEFT JOIN FolderDocument fdd
ON hr.DocNumber = fdd.DocNumber
LEFT JOIN FolderDocument fdf
ON hr.ParentNumber = fdf.DocNumber
WHERE RankNum = 1

请注意,此返回多个顶级文件夹(如果存在)。如果要实现打破平局,请将RANK()函数更改为ROW_NUMBER()并使用OVER中的ORDER BY子句指定确定“获胜者”的顺序。

此解决方案还假定FolderDocument包含树的顶级节点(它们本身具有空父项)的记录。如果不是这样的话,很容易将最终查询更改为从Root表中查找顶级节点。

我已经制作了一个SQLFiddle来显示多个顶级文件夹和一个参差不齐的层次结构的处理。

按请求编辑: 要使用Root作为父文件夹名称的源,您可以在最终查询中执行此操作:

SELECT hr.DocNumber, hr.ParentNumber AS TopFolderNumber, fdd.Name AS DocName, r.Name AS TopFolderName
FROM HierarchyRank hr
LEFT JOIN FolderDocument fdd
ON hr.DocNumber = fdd.DocNumber
LEFT JOIN Root r
ON hr.ParentNumber = r.DocNumber
WHERE RankNum = 1