【问题标题】:SQL Server recursive hierarchical query, less than optimal data structureSQL Server递归分层查询,数据结构不够优化
【发布时间】:2016-09-18 01:21:08
【问题描述】:

我有一个带有 SQL Server 2008 R2 数据库的商业应用程序,其中包含一个应该对文件和文件夹结构进行建模的表,类似于 ::..:。数据库表包含成对的值(folder_item、parent),其中 folder-item 是文档或文件夹,而 parent 是指向表中另一行的链接。

我正在尝试编写一个每行返回两个值的查询:

  • 一份文件
  • 文档的完整连接路径,从顶级文件夹到文档的直接容器,例如 Root:Level1:Level2..:LevelN。

通常,递归查询应该能够处理这种情况,但有一个复杂的问题。 Folder Item 表包含每个文档和子级别的冗余条目,将它们与文件夹结构中的每个祖先配对,而不仅仅是它们的直接父级。

而不是 (文件,父母) (父母,祖父母) (祖父母,曾祖父母) ... (祖先,根)

该表包含 (文件,父母) (文件,祖父母) ... (文件,祖先) (文档,根) (父母,祖父母) ... (父母,祖先) (父母,根) ... (祖父母,曾祖父母) ... (祖父母,根)

等等。我确信数据建模者有他们设计的理由,但它否定了标准递归分层查询的使用。事实上,当我尝试时,执行超过了递归级别的最大数量。

有没有其他人遇到过类似的问题,是否可以在不借助标准 SQL 功能之外的复杂编程的情况下解决?

非常感谢

帕特里克

【问题讨论】:

  • 发布一些表结构和示例数据怎么样?如果您只是将递归基于名称,您可能会打一场失败的战斗。
  • 递归基于唯一但非 PK VARCHAR 值“DOCNUMBER”,其中 PARENT 列包含祖先行的 DOCNUMBER。
  • 幸运的是,事实证明已决定忽略现有的文件夹层次结构,并且由于一次(明智的)业务决策,问题已经消失。感谢 Sean 和 Tab 的回答..

标签: sql-server recursion hierarchical


【解决方案1】:

如果你有:

(文档, 父) (文档, 祖父母) ... (文档, 祖先) (文档,根)(父母,祖父母)...(父母,祖先)(父母,根)...(祖父母,曾祖父母)...(祖父母,根)

您只想将递归限制为:

(文档,父母)(父母,祖父母)(祖父母,曾祖父母)(曾祖父母,根)

对吗?因此,诀窍就是弄清楚在递归 cte 的下半部分放置什么条件,这样当前行的每个相对对象都不会连接到当前行。

所以对于document,您需要parent。对于parent,您需要grandparent 等等。我们如何创建这个过滤器?

对于document 而言,parent 的真实情况与任何其他祖先都不真实吗?

答案:documentparent 具有所有相同的亲属,但只有 document 具有 parent 作为祖先。

因此,当您查看每个文件夹项的父项时,如果存在另一行,其中该父项的父项与当前项的父项之一相同,则该文件夹项不是当前文件夹项的直接父项,并且应该是过滤掉递归连接。

想象一个采访:“所以你是我的祖先之一。如果我的其他祖先都没有你作为祖先,那么你一定是我的直系父母。”

是的,不是吗?

我没有要测试的结构,但我想在递归连接中添加这样的东西会起作用,但它可能需要一些调整...

{for recursion -- Join second half of UNION back to main CTE}
ON bottom.Folder_Item=cte.parent  --you are my ancestor
AND NOT EXISTS(
 SELECT * FROM MyTable mt --others
 WHERE mt.folder_item<>bottom.folder_item --the other is not you
 AND mt.Folder_Item=cte.parent --the other is also my ancestor
 AND mt.Parent=bottom.folder_item --the other also has you as ancestor
)

对于这个 sn-p,bottom 是我递归 UNION 下半部分的别名,cte 是整个 CTE 的别名。

并且通过将此过滤器置于递归的 JOIN 条件中,我认为它应该可以防止递归树变得疯狂并超出递归限制。我认为

如果您仍然得到递归限制,请尝试在递归 CTE 之前在 CTE 中以这种方式预过滤您的表,以便在执行递归之前预先消除所有非直接祖先。

我认为这应该能够工作,但如果不能,你绝对可以用 CURSOR 做你需要的。

【讨论】:

    猜你喜欢
    • 2015-11-23
    • 2014-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-22
    • 2017-02-04
    相关资源
    最近更新 更多