Sum the values without using cursor/loop within a table

  • Hello,

    I am wondering if we can get the desire result without using cursor/loop. I have a table with sample data as below:

    RecordID ParentRecordIDCredit

    1 NULL 10

    2 NULL 5

    3 1 7

    4 1 8

    5 2 15

    7 5 10

    Now i want to write a t-sql statement without using cursor/loop which will do the sum of the credits of all the child records (including parent record) for the parent records whose ParentRecordId is NULL. So it means for the RecordID 2, it should add the credit of RecordID 2,5 and 7.

    So the result will look like below:

    RecordIDTotal Credits

    125

    230

    -Deepak

  • Off the top of my head....

    with cteResursive(BaseRecordId,RecordID, ParentRecordID, Credit)

    as

    (

    Select RecordId,RecordId,ParentRecordId,Credit

    from yourTab

    where ParentRecordId is null

    union all

    Select BaseRecordId,RecordId,ParentRecordId,Credit

    from cteResursive join yourTab on YourTab.ParentNodeId = cteResursive.RecordID

    )

    Select BaseRecordId,sum(credit)

    from cteRecursive

    group by BaseRecordId



    Clear Sky SQL
    My Blog[/url]

  • This is one way to get it:

    DECLARE @test-2 TABLE (

    RecordID int,

    ParentRecordId int,

    Credit int

    )

    INSERT INTO @test-2 VALUES (1, NULL, 10)

    INSERT INTO @test-2 VALUES (2, NULL, 5)

    INSERT INTO @test-2 VALUES (3, 1, 7)

    INSERT INTO @test-2 VALUES (4, 1, 8)

    INSERT INTO @test-2 VALUES (5, 2, 15)

    INSERT INTO @test-2 VALUES (7, 5, 10)

    SELECT RecordId, SumCredit = Credit + (SELECT SUM(Credit) FROM @test-2 WHERE ParentRecordId = SRC.RecordID)

    FROM @test-2 AS SRC

    WHERE ParentRecordId IS NULL

    -- Gianluca Sartori

  • Dave Ballantyne (7/14/2009)


    Off the top of my head....

    with cteResursive(BaseRecordId,RecordID, ParentRecordID, Credit)

    as

    (

    Select RecordId,RecordId,ParentRecordId,Credit

    from yourTab

    where ParentRecordId is null

    union all

    Select BaseRecordId,RecordId,ParentRecordId,Credit

    from cteResursive join yourTab on YourTab.ParentNodeId = cteResursive.RecordID

    )

    Select BaseRecordId,sum(credit)

    from cteRecursive

    group by BaseRecordId

    Nice, I vote for your solution Dave. I didn't see it and I posted mine.

    -- Gianluca Sartori

  • Dave, it does not work. It throws the following error:

    Msg 530, Level 16, State 1, Line 1

    The statement terminated. The maximum recursion 100 has been exhausted before statement completion.

    I swap the joining fields for both tables in the "On" clause to stop the infinite recursion, but in that case, I get the different result.

    -Deepak

  • Why this problem is different with others is that here the t-sql statement should be able to sum the credits of n level of child records for the main parent record.

    A CTE works for the child records which have direct relationship to parent records. But what about the child records which has indirect relationship to their parent's parent record.

    It seems that only solution here is to use cursor......

    What all other think?

  • Small correction...

    with cteResursive(BaseRecordId,RecordID, ParentRecordID, Credit)

    as

    (

    Select RecordId,RecordId,ParentRecordId,Credit

    from yourTab

    where ParentRecordId is null

    union all

    Select BaseRecordId,RecordId,ParentRecordId,Credit

    from cteResursive join yourTab on YourTab.ParentRecordID = cteResursive.RecordID

    where ParentRecordId is not null

    )

    Select BaseRecordId,sum(credit)

    from cteRecursive

    group by BaseRecordId

    If you run that and you get the recursive error please post DDL and sample data



    Clear Sky SQL
    My Blog[/url]

  • Deepak Jain (7/14/2009)


    It seems that only solution here is to use cursor......

    I already posted a solution without cursors. If you can't get Dave's one to work, use mine.

    There are very few things that can't be done without cursors.

    -- Gianluca Sartori

  • Hi Gianluca,

    Your solution too has a bug. It is not adding the third level of child. When I run it, it gives the following result:

    RecordID SumCredit

    125

    220

    The Sum of RecordID 2 should be 30 not 20 as it needs to add the credit of itself and all it's direct and indirect child i.e. RecordId 5 and 7.

    -Deepak

  • No luck dave,

    Here is the DDL and Sample data:

    DECLARE @RTest TABLE

    (

    RecordID int,

    ParentRecordId int,

    Credit int

    )

    INSERT INTO @RTest VALUES (1,NULL,10)

    INSERT INTO @RTest VALUES (2,NULL,5)

    INSERT INTO @RTest VALUES (3,1,7)

    INSERT INTO @RTest VALUES (4,1,8)

    INSERT INTO @RTest VALUES (5,2,15)

    INSERT INTO @RTest VALUES (7,5,10)

    -Deepak

  • Tried and tested solution

    create table #t1(

    RecordID integer,

    ParentRecordID integer,

    Credit integer)

    go

    insert into #t1 values(1, NULL, 10)

    insert into #t1 values(2, NULL, 5)

    insert into #t1 values(3, 1, 7)

    insert into #t1 values(4, 1, 8)

    insert into #t1 values(5, 2, 15)

    insert into #t1 values(7, 5 ,10)

    go

    with cteRecursive(BaseRecordId,RecordID, ParentRecordID, Credit)

    as

    (

    Select RecordId,RecordId,ParentRecordId,Credit

    from #t1 yourTab

    where ParentRecordId is null

    union all

    Select BaseRecordId,yourTab.RecordId,yourTab.ParentRecordId,yourTab.Credit

    from cteRecursive join #t1 yourTab on YourTab.ParentRecordID = cteRecursive.RecordID

    where yourTab.ParentRecordId is not null

    )

    Select BaseRecordId,sum(credit)

    from cteRecursive

    group by BaseRecordId

    go



    Clear Sky SQL
    My Blog[/url]

  • Deepak Jain (7/14/2009)


    Hi Gianluca,

    Your solution too has a bug. It is not adding the third level of child. When I run it, it gives the following result:

    RecordID SumCredit

    125

    220

    The Sum of RecordID 2 should be 30 not 20 as it needs to add the credit of itself and all it's direct and indirect child i.e. RecordId 5 and 7.

    -Deepak

    You're right. Sorry for posting a wrong qry.

    I still believe you can work around Dave's suggestions. Cursor based code can almost every time be converted to set based.

    -- Gianluca Sartori

  • Wow!!! It works great!!!

    Thanks Dave, and Gianluca you too.

    -Deepak

  • Hi deepak,

    I am just curius to know whether the above solution worked for 4th, 5th level of the child records. I tried here with some sample data but didnt get the desired output.

  • manish.singh (7/17/2009)


    Hi deepak,

    I am just curius to know whether the above solution worked for 4th, 5th level of the child records. I tried here with some sample data but didnt get the desired output.

    It should work to the 100th level , if you get that deep you can override with the MAXRECURSION(X) option.

    If it doesent , post some sample data and ill take a look.



    Clear Sky SQL
    My Blog[/url]

Viewing 15 posts - 1 through 14 (of 14 total)

You must be logged in to reply to this topic. Login to reply