Domanda

I have a table of companies, with three columns: 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

So my query identifies that A holds 25% of B, A holds 50% of C and A holds a further 5% of B through it's 50% holding in C and a further 12.5% of C through the holding in B.

I was super super happy with myself as for once I'd nailed some sql. This did not last long. I noticed that with the mutual ownership of B and C, this sends the query into an infinite loop. I have tried stopping the loop by putting a max on the loops, but this gives ownerships in some cases still above 100%... besides, it's just not correct.

Any ideas on how else I would do this other than:

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
È stato utile?

Soluzione

Try stopping your iteration on the Recursive block of your CTE instead of doing it outside, my guess is if you stop it while SQL is trying to build it (inside the recursive block) it wont get into a infinite loop

  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

Altri suggerimenti

This will give you what you want. It first creates a hierarchy and then iterates through it and finally sums the aggregates to get you the total holding. As long as neither the HOLDER_CO_ID or HELD_CO_ID have a | in them this will work...

/*
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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top