Home Forums SQL Server 2008 T-SQL (SS2K8) Interesting Question related to Splitting table row conditionally RE: Interesting Question related to Splitting table row conditionally

  • uravindarreddy (6/21/2013)


    HI dwain!!!

    Could you help me in generating script with CURSOR?

    Even with CURSOR it is bit tricky.

    I am not able to find a perfect script for different kinds of data scenarios.

    I think this will do it for you with a CURSOR, and believe me when I say this is quite a challenge for me (remembering the syntax) since I rarely ever use or recommend them. Note that I'm using temp tables and I haven't tested for cases where there are multiple policy IDs for both members and receipts (because you didn't give me sample data) but I wrote the code trying to cover that case.

    CREATE TABLE #Receipt

    (ReceiptID int NOT NULL IDENTITY(1,1)

    ,PolicyID int NOT NULL

    ,ReceiptAmt NUMERIC(17,2) NOT NULL);

    INSERT INTO #Receipt (PolicyID, ReceiptAmt)

    SELECT 11, 3000 UNION ALL SELECT 11, 5000 UNION ALL SELECT 11, 1200;

    CREATE TABLE #MemberPremiumDet

    (MemberID int NOT NULL IDENTITY(1,1)

    ,PolicyID int NOT NULL

    ,PremiumAmt NUMERIC(17,2) NOT NULL);

    INSERT INTO #MemberPremiumDet (PolicyID, PremiumAmt)

    SELECT 11, 1200 UNION ALL SELECT 11, 1600 UNION ALL SELECT 11, 2200

    UNION ALL SELECT 11, 2456 UNION ALL SELECT 11, 1144;

    CREATE TABLE #ReceiptsMatched

    (MemberID int NOT NULL

    ,ReceiptID int NOT NULL

    ,PolicyID int NOT NULL

    ,ReceiptAmt NUMERIC(17,2)

    ,ConsumedAmt NUMERIC(17,2)

    ,BALAmt NUMERIC(17,2)

    ,PRIMARY KEY (ReceiptID, MemberID));

    DECLARE @ReceiptID INT, @PolicyID INT, @ReceiptAmt NUMERIC(17,2)

    ,@RemainingPremium NUMERIC(17,2) = 0

    ,@MemberID INT = (SELECT TOP 1 MemberID FROM #MemberPremiumDet ORDER BY PolicyID, MemberID);

    DECLARE Receipts CURSOR FOR

    SELECT ReceiptID, PolicyID, ReceiptAmt

    FROM #Receipt

    --WHERE ReceiptID = 1

    ORDER BY PolicyID, ReceiptID;

    OPEN Receipts;

    FETCH NEXT

    FROM Receipts

    INTO @ReceiptID, @PolicyID, @ReceiptAmt;

    WHILE @@FETCH_STATUS = 0

    BEGIN

    WITH Matching AS (

    SELECT MemberID, ReceiptID, ReceiptAmt=b.ReceiptAmt

    ,ConsumedAmt=CAST(

    CASE WHEN a.PremiumAmt - @RemainingPremium < b.ReceiptAmt

    THEN a.PremiumAmt - @RemainingPremium

    ELSE 0

    END AS NUMERIC(17,2))

    ,BalAmt=CAST(

    CASE WHEN 0 < b.ReceiptAmt - (a.PremiumAmt - @RemainingPremium)

    THEN b.ReceiptAmt - (a.PremiumAmt - @RemainingPremium)

    ELSE 0

    END AS NUMERIC(17,2))

    ,a.PolicyID

    FROM #MemberPremiumDet a

    INNER JOIN #Receipt b ON a.PolicyID = b.PolicyID

    WHERE b.ReceiptID = @ReceiptID AND a.PolicyID = @PolicyID AND a.MemberID = @MemberID

    UNION ALL

    SELECT a.MemberID, ReceiptID, ReceiptAmt=b.BalAmt

    ,ConsumedAmt=CASE WHEN a.PremiumAmt < b.BalAmt THEN a.PremiumAmt ELSE b.BalAmt END

    ,BalAmt=CAST(CASE WHEN 0 < b.BalAmt-a.PremiumAmt THEN b.BalAmt-a.PremiumAmt ELSE 0 END AS NUMERIC(17,2))

    ,a.PolicyID

    FROM #MemberPremiumDet a

    INNER JOIN Matching b ON a.PolicyID = b.PolicyID AND a.MemberID = b.MemberID + 1

    WHERE BalAmt > 0

    )

    INSERT INTO #ReceiptsMatched

    SELECT MemberID, ReceiptID, PolicyID, ReceiptAmt, ConsumedAmt, BalAmt

    FROM Matching;

    SELECT TOP 1 @RemainingPremium=ConsumedAmt

    ,@MemberID=MemberID

    FROM #ReceiptsMatched

    ORDER BY PolicyID, MemberID DESC, ReceiptID DESC;

    FETCH NEXT

    FROM Receipts

    INTO @ReceiptID, @PolicyID, @ReceiptAmt;

    END

    -- Desired results

    --1 1 3000 1200 1800

    --2 1 1800 1600 200

    --3 1 200 200 0

    --3 2 5000 2000 3000

    --4 2 3000 2456 544

    --5 2 544 544 0

    --5 3 1200 600 600

    SELECT * FROM #ReceiptsMatched;

    GO

    DROP TABLE #Receipt;

    DROP TABLE #MemberPremiumDet;

    DROP TABLE #ReceiptsMatched;

    CLOSE Receipts;

    DEALLOCATE Receipts;

    It may be possible to do this with a Quirky Update (QU) but that's gonna be really tricky. Tried a bit but couldn't get it to fully work. May try again but this solution may actually work faster than the QU would. It would probably depend on how many members get allocated an individual receipt.


    My mantra: No loops! No CURSORs! No RBAR! Hoo-uh![/I]

    My thought question: Have you ever been told that your query runs too fast?

    My advice:
    INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
    The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.

    Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
    Since random numbers are too important to be left to chance, let's generate some![/url]
    Learn to understand recursive CTEs by example.[/url]
    [url url=http://www.sqlservercentral.com/articles/St