SQL RECURSIVE TABLE INFINITE LOOP

时间:2014-04-02 20:38:25

标签: sql sql-server recursive-query

我有一个公司表,有三列:holder_co_id,held_co_id,pct_owned。

holder_co_id  held_co_id  pct_owned
A             B           25
A             C           50
B             C           50
C             B           10

所以我的查询确定A持有25%的B,A持有50%的C,而A持有另外5%的B通过它持有50%的C和另外12.5%的C通过抱着B。

我对自己非常满意,因为我曾经钉过一些sql。这并没有持续多久。我注意到,通过B和C的共同所有权,这会将查询发送到无限循环中。我已经尝试通过在循环上放置一个最大值来停止循环,但是在某些情况下这会使所有权仍然高于100%...此外,它只是不正确。

除了:

之外我还会怎么做呢?
WITH Result AS 
(SELECT HOLDER_CO_ID, 
        HELD_CO_ID, 
        PCT_OWNED, 
        1 AS generationsremoved
FROM dbo.ALL_HOLDING_INFO
UNION ALL
SELECT  P.HOLDER_CO_ID, 
        N.HELD_CO_ID, 
        P.PCT_OWNED * N.PCT_OWNED AS Expr1,
        P.generationsremoved + 1 AS Expr2
FROM  Result AS P INNER JOIN
dbo.ALL_HOLDING_INFO AS N ON P.HELD_CO_ID = N.HOLDER_CO_ID
WHERE     (P.generationsremoved <= 10))
SELECT DISTINCT TOP (100) PERCENT HOLDER_CO_ID, 
                                  HELD_CO_ID, 
                                  PCT_OWNED, 
                                  generationsremoved
 FROM         Result AS Result_1
 WHERE     (PCT_OWNED > 0.005)
 ORDER BY HOLDER_CO_ID, HELD_CO_ID, generationsremoved DESC

2 个答案:

答案 0 :(得分:2)

尝试停止CTE iteration上的Recursive block,而不是在外面执行此操作,我的猜测是,如果您在SQL尝试构建它(在递归块内)时停止它,它将无法获得进入一个无限循环

  WITH Result AS 
    (SELECT HOLDER_CO_ID, 
            HELD_CO_ID, 
            PCT_OWNED, 
            1 AS generationsremoved
    FROM dbo.ALL_HOLDING_INFO
    UNION ALL
    SELECT  P.HOLDER_CO_ID, 
            N.HELD_CO_ID, 
            P.PCT_OWNED * N.PCT_OWNED AS Expr1,
            P.generationsremoved + 1 AS Expr2
    FROM  Result AS P INNER JOIN
    dbo.ALL_HOLDING_INFO AS N ON P.HELD_CO_ID = N.HOLDER_CO_ID
    WHERE     (P.generationsremoved<= 10)
      AND (PCT_OWNED > 0.005))
    SELECT DISTINCT TOP (100) PERCENT HOLDER_CO_ID, 
                                      HELD_CO_ID, 
                                      PCT_OWNED, 
                                      generationsremoved
     FROM         Result AS Result_1

答案 1 :(得分:1)

这会给你你想要的。它首先创建一个层次结构然后遍历它,最后总结聚合以获得总持有量。只要HOLDER_CO_ID或HELD_CO_ID都没有|,这就行了......

/*
If      Object_ID('dbo.ALL_HOLDING_INFO') Is Not Null Drop Table dbo.ALL_HOLDING_INFO
Create  Table dbo.ALL_HOLDING_INFO (HOLDER_CO_ID Varchar(10), HELD_CO_ID Varchar(10), PCT_OWNED Float)

Insert  dbo.ALL_HOLDING_INFO
Values ('A', 'B', .25),('A', 'C', .50),('B' ,'C', .50),('C','B',.10);
*/


With    Hierarchy As
(
        Select  Distinct HOLDER_CO_ID As HOLDER_CO_ID, 
                HELD_CO_ID As HELD_CO_ID,
                PCT_OWNED,
                Convert(Varchar(Max),'|' + HELD_CO_ID + '|') As AllChildren, 
                0 As RelationDepth
        From    dbo.ALL_HOLDING_INFO
        Union   All
        Select  h.HOLDER_CO_ID, 
                a.HELD_CO_ID As HELD_CO_ID,
                a.PCT_OWNED,
                Convert(Varchar(Max),h.AllChildren + a.HELD_CO_ID) + '|' As AllChildren, 
                h.RelationDepth + 1
        From    Hierarchy h
        Join    dbo.ALL_HOLDING_INFO a
                On  h.HELD_CO_ID = a.HOLDER_CO_ID
        Where   h.HOLDER_CO_ID != a.HELD_CO_ID
        And     h.AllChildren Not Like '%|' + a.HELD_CO_ID + '|%'
), Result AS 
(
        SELECT  Row_Number() Over (Order By Holder_CO_ID, PCT_OWNED) As tID,
                HOLDER_CO_ID, 
                HELD_CO_ID, 
                PCT_OWNED, 
                RelationDepth
        FROM    Hierarchy
        Where   RelationDepth = 0
        UNION   ALL
        SELECT  p.tID,
                P.HOLDER_CO_ID, 
                N.HELD_CO_ID, 
                P.PCT_OWNED * N.PCT_OWNED AS Expr1,
                n.RelationDepth
        FROM    Result AS P 
        JOIN    Hierarchy AS N 
                ON  P.HOLDER_CO_ID = N.HOLDER_CO_ID
                And p.HELD_CO_ID != n.HELD_CO_ID
                And p.RelationDepth = n.RelationDepth - 1
)
SELECT  HOLDER_CO_ID, HELD_CO_ID, SUM(PCT_OWNED)*100 As PCT_OWNED                             
FROM    Result AS Result_1
Group   By HOLDER_CO_ID, HELD_CO_ID
ORDER   BY HOLDER_CO_ID, HELD_CO_ID DESC