【问题标题】:Recursive Query using to columns to two columns使用到列到两列的递归查询
【发布时间】:2018-10-22 00:09:50
【问题描述】:

我有一个系统,其中我有递归链接的文档,我需要创建一个查询来检测源文档。

我已经能够使用带有 While 的存储过程来实现相同的功能,但是性能很糟糕,因为我必须处理大约 100 万条记录。有关如何实现此递归查询/SP 的任何建议?

在下面的示例中,我找到了文档 O - 12345,我需要找到原始文档 (A - 29503)。我所有的原始文档都以 DocumentType = A 开头。

DocumentType    CodDocument DocumentTypeOrigin  CodDocumentOrigin 
O               12345       E                   32456
E               32456       P                   98472
P               98472       A                   29503
A               29503       

我想得到像(已编辑)这样的输出:

DocumentType    CodDocument DocumentTypeOrigin  CodDocumentOrigin FinalDocumentTypeOrigin   FinalCodDocumentOrigin 
O               12345       E                   32456             A             29503       
E               32456       P                   98472             A             29503       
P               98472       A                   29503             A             29503       
A               29503                                             A             29503       

感谢您的帮助!

【问题讨论】:

  • 那么,您期望的输出是什么?
  • 注意:递归查询通常并不比使用 While 或 Cursors 更好或更差。特别是对于单次查找(相对于批量查询和 DML)。
  • 定义明确的游标通常比while循环快
  • @Larnu,我已经编辑了我的问题以获得预期的结果。基本上我需要的是在每个文档中都有开始这个递归行的文档。
  • 您可能对此感兴趣;这是与正常 rCTE 完全不同的方法:Hierachies on Steroids

标签: sql sql-server recursion sql-server-2014


【解决方案1】:

使用递归 CTE,您可以执行以下操作:

WITH RECURSIVE docSearch AS
(
    --Starting point
    SELECT
        DocumentType as starting_doctype, 
        CODDocument as starting_coddoc,
        DocumentType as child_doctype, 
        CODDocument as child_coddoc,
        DocumentTypeOrigin as parent_doctype,
        CODDocumentTypeOrigin as parent_coddoc,
        1 as level
    FROM yourtable
    WHERE documenttype = 'O' and CodDocument = '12345'

    UNION ALL

    --Recursive SQL (refers back to the the CTE that we are currently in    
    SELECT
        docSearch.starting_doctype,
        docSearch.starting_coddoc,
        docSearch.parent_doctype as child_doctype,
        docSearch.parent_coddoc as child_coddoc,
        DocumentTypeOrigin as parent_doctype,
        CODDocumentTypeOrigin as parent_coddoc,
        level + 1 as level
    FROM
        docSearch
        INNER JOIN yourTable 
            ON docSearch.parent_doctype = yourTable.DocumentType
                AND docSearch.parent_coddoc = yourTable.CodDocument
    WHERE level < 20 --prevent cycling/endless loops
)
--Now select from the CTE for the max docSearch
SELECT * FROM docSearch WHERE level = (SELECT max(level) FROM docSearch);

不能保证这会更快,但是...您可能会发现您想删除顶部 SELECT 语句中的 WHERE 子句,以便为每个 DocTypeCodDocument 构建此表(如果您正在这样做)经常搜索。然后只需将结果写入一个新表,然后执行所有的 SELECTING 操作。

【讨论】:

  • 这适用于一种情况...但是如果我评论 WHERE 语句(WHERE documenttype = 'O' and CodDocument = '12345'),我将省略几个文档,因为我不知道数字每个文档中的级别。
  • 如果省略 WHERE 子句,则只需在最终选择中的递归 CTE 上执行 SELECT *。你必须调整那个东西才能从递归结果中得到你想要的东西。像SELECT CASE WHEN level = max(level) OVER (PARTITION BY DocumentType, CodDocument) THEN 'DeepestLevel' END .... 这样的东西,然后保持DeepestLevel
  • 谢谢...查询在不到 9 分钟的时间内返回超过 300 万行...我在最后的语句中进行了交叉申请以获得最大级别..
  • SELECT * FROM docSearch doc WITH (NOLOCK) CROSS APPLY (SELECT MAX(level) maxlevel FROM docSearch doc1 WITH (NOLOCK) WHERE doc1.starting_doctype = doc.starting_doctype AND doc1.starting_coddoc = doc.starting_coddoc ) QRY WHERE doc.level = QRY.maxlevel
【解决方案2】:

对于要返回的所有文档,我建议使用临时表来保存结果。然后在循环中一次更新每条记录的 FinalDocumentTypeOrigin 和 FinalCodDocumentOrigin 字段,一次升级一个级别。当没有记录更新或达到某个级别限制时终止循环。只需比最大链接级别多循环 1 次。

【讨论】:

  • 我的想法是创建一个临时表来最小化工作,但是我的源表没有时间戳,所以我必须处理大量的行
【解决方案3】:

I have a short writeup on another SO question 询问嵌套关系,说明如何使用hierarchyid 数据类型填充数据类型,然后查询这些类型的嵌套关系。

【讨论】:

    猜你喜欢
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 1970-01-01
    • 2014-12-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多