【问题标题】:SQL Server update within recursive query递归查询中的 SQL Server 更新
【发布时间】:2014-03-24 15:06:25
【问题描述】:

我正在使用 Microsoft SQL Server 2008 并尝试使用递归查询完成与这篇文章非常相似的事情:Recursive Child/Parent queries in T/SQL

我自然会尝试简化事情;希望我已经以明确的方式这样做了。我的桌子看起来像这样:

Parent  Child
A       A
A       B
B       D
D       H
D       I
A       C
C       E
E       C
E       J
E       K
C       F
C       G

视觉上的关系看起来像这样:

A
    B
        D
            H
            I
    C
        E
            C
            J
            K
        F
        G

我需要在表中创建一个新列,表示子实体到顶层的路径(在本例中为 A):

Parent  Child  Chain
A       A      A
A       B      A,B
B       D      A,B,D
D       H      A,B,D,H
D       I      A,B,D,I
A       C      A,C
C       E      A,C,E
E       C      A,C,E,C
E       J      A,C,E,J
E       K      A,C,E,K
C       F      A,C,F
C       G      A,C,G

其中的皱纹,以及父子可能不是此处使用的术语的原因可以从实体 C 中看出,实体 C 既是实体 E 的父对象,又是实体 E 的子对象,这会导致无限的递归循环。

我的想法是更新递归循环中的链值,并限制对链列中具有 NULL 值的实体的递归调用。这个想法是仅在第一次遇到实体时递归实体。我没有工作,我不确定如何将更新集成到递归调用中:

WITH r(parent,child,mychain)
AS
(
    SELECT parent, child, child AS myChain 
    FROM myTable 
    WHERE parent = 'A' AND
    parent <> child AND
    chain IS NULL
    UNION ALL
    SELECT v.parent, v.child, myChain + ',' + v.child AS myChain 
    FROM myTable v
    INNER JOIN r ON r.child = v.parent
    WHERE v.parent <> v.child
)
UPDATE myTable
SET chain = r.myChain
FROM myTable AS c
JOIN r ON c.ID = r.ID

关于我如何实现这一点的任何建议?

提前致谢。

编辑:

我可能有点过于简单化了。因为父列和子列的实际值很长(大约 20 多个字符),所以我真的需要使用记录 id 与值相对应来创建一个链。我修改了西蒙的建议,如下所示。这让我非常接近;但是,C -> E 记录没有得到输出(所有记录最终都应该随链更新)。可能没关系;我仍在努力解决它。

with r as
(
    SELECT id, parent, child, 
      CAST( id AS VARCHAR(1024) ) AS CHAIN,
      0 as level
    FROM myTable 
    WHERE id = '1' 


    UNION ALL
    SELECT c.id, c.parent, c.child, 
      cast( (r.CHAIN + ',' + CAST( c.id AS varchar(10)) ) AS varchar(1024)) AS CHAIN,
      r.level + 1 as level
    FROM myTable c
    JOIN r
      ON r.child = c.parent
    WHERE c.parent != c.child AND r.parent != c.child

)
select * from r order by r.level, r.parent, r.child; 

【问题讨论】:

  • 见下文。这对你有用吗?

标签: sql-server-2008 recursion sql-update common-table-expression


【解决方案1】:

试试这个:

with r as
(
    SELECT parent, child, 
      CAST( (parent + ',' + child) AS VARCHAR(10)) AS chain, 
      0 as level
    FROM myTable 
    WHERE parent = 'A' 
    AND parent != child

    UNION ALL
    SELECT c.parent, c.child, 
      cast((r.chain + ',' + c.child) as varchar(10)) AS chain, 
      r.level + 1 as level
    FROM myTable c
    JOIN r
      ON r.child = c.parent
    WHERE r.chain NOT LIKE '%,' + c.child + ',%'

)
select * 
from r 
order by r.level, r.parent, r.child; 

查看:SQL Fiddle

【讨论】:

  • 您可能可以删除演员表。 SQL fiddle 似乎需要它们,但我认为 sql server 不需要。
  • 西蒙,感谢您的回复。我想你让我接近了。我已经成功地在一些顶级实体上针对我的真实数据运行了这个,但是在达到我设置的 5000 次递归的限制后,我还有其他人超时。我仍在努力弄清楚达到这个限制是否有意义。
  • 那你一定有更深的周期。上面的代码使用“WHERE c.parent != c.child AND r.parent != c.child”防止像 c=>e=>c 这样的循环
  • 添加了任何周期长度的检查。我以为你只需要更简单的用例。
  • 它确实有效,它回答了原始问题,所以我将把它标记为已回答。我会注意到,虽然我无法让它使用 ID 而不是子值来构建链(因为在附加链时我们有子值但没有它的 ID)。感谢您的帮助西蒙!
猜你喜欢
  • 1970-01-01
  • 2014-12-19
  • 2012-12-05
  • 1970-01-01
  • 1970-01-01
  • 2014-10-10
  • 2011-02-21
  • 1970-01-01
相关资源
最近更新 更多