2

I've searched and tried for long hours, and can't seem to get what I need. I have a table of accounts as a tree -parents and children-, only leaf accounts can have transactions, any parent will NOT have debits and credits itself.

My fiddle of data is here

What I need is to show sum of "Debits of children" and sum of "Credits of children" in their parent's row, like this picture:

enter image description here

How can I do it in MySql?

Thank you

2 Answers 2

2

With your example, you can run

CREATE PROCEDURE procedure_name()
BEGIN
        DECLARE finished INTEGER DEFAULT 0;
        DECLARE _accoujntno INTEGER DEFAULT 0;
        DECLARE _uacn varchar(191) DEFAULT "";
    DEClARE curaccount 
        CURSOR FOR 
            Select account_no ,user_account_number FROM TBL1 WHERE length(user_account_number)-length(replace(user_account_number,'-',''))+1  = 2 order by user_account_number;

    -- declare NOT FOUND handler
    DECLARE CONTINUE HANDLER 
        FOR NOT FOUND SET finished = 1;
        
        CREATE TEMPORARY TABLE credits(
        user_account_number VARCHAR(191),
        `Debit_Before_Period` DECIMAL(20,2),
         `Credit_Before_Period` DECIMAL(20,2),
         `Debit_In_Period` DECIMAL(20,2),
         `Credit_In_Period` DECIMAL(20,2)
        );
        
        OPEN curaccount;

    getaccount: LOOP
        FETCH curaccount INTO _accoujntno,_uacn;
        IF finished = 1 THEN 
            LEAVE getaccount;
        END IF;
                INSERT INTO credits SELECT _uacn ,SUM(`Debit Before Period`),SUM(`Credit Before Period`) ,SUM(`Debit In Period`) ,SUM(`Credit In Period`)  
                FROM TBL1 
                WHERE LEFT(user_account_number,7) = _uacn AND account_no <> _accoujntno;
    END LOOP getaccount;
    CLOSE curaccount;

   SELECT * FROM credits;
END 

The resulting temporary table credits you can use to run further analysis

simply add the procedure and CALL procedure_name()

In a query tab in phmyadmin wor mysql Workbench you need to add DELIMITER to the procedure, but that doesn't work in dbfiddle

example

It is like in the comment

CREATE PROCEDURE procedure_name()
BEGIN
        DECLARE finished INTEGER DEFAULT 0;
        DECLARE _accoujntno INTEGER DEFAULT 0;
        DECLARE _uacn varchar(191) DEFAULT "";
    DEClARE curaccount 
        CURSOR FOR 
            Select account_no ,user_account_number FROM TBL1 WHERE length(user_account_number)-length(replace(user_account_number,'-',''))+1  = 1 order by user_account_number;

    -- declare NOT FOUND handler
    DECLARE CONTINUE HANDLER 
        FOR NOT FOUND SET finished = 1;
        
        CREATE TEMPORARY TABLE credits(
        user_account_number VARCHAR(191),
        `Debit_Before_Period` DECIMAL(20,2),
         `Credit_Before_Period` DECIMAL(20,2),
         `Debit_In_Period` DECIMAL(20,2),
         `Credit_In_Period` DECIMAL(20,2)
        );
        
        OPEN curaccount;

    getaccount: LOOP
        FETCH curaccount INTO _accoujntno,_uacn;
        IF finished = 1 THEN 
            LEAVE getaccount;
        END IF;
                INSERT INTO credits SELECT _uacn ,SUM(`Debit Before Period`),SUM(`Credit Before Period`) ,SUM(`Debit In Period`) ,SUM(`Credit In Period`)  
                FROM TBL1 
                WHERE LEFT(user_account_number,3) = _uacn;
    END LOOP getaccount;
    CLOSE curaccount;

   SELECT * FROM credits;
END 

new example

5
  • Thank you for helping. But it seems to partially work, accounts in level 1 like '001' and level 3 for example like '003-006-001' are missing from result set 3 in the dbFiddle
    – Abeer Sul
    Commented Sep 6, 2020 at 15:00
  • the image shows that you only wanr level 3 and above. the image shows 001-001 and exclude 003, but basically you know now a way how you can achieve it. The cursor determines which level are the base for the rest, also the routine excludes the level two from the sums, wheb you remove AND account_no <> _accoujntno the level is not excluded anymore
    – nbk
    Commented Sep 6, 2020 at 16:04
  • can you please explain more in the answer? I don't understand your code. I did as you said, removed the condition and still didn't see all levels in the result. The image shows example of summing child levels into their parents row, starting from lowest level whether 4 or 5 or 6.. up to level 1. I want to fiddle with your code to reach the goal but I don't understand it clearly. Thanks again
    – Abeer Sul
    Commented Sep 6, 2020 at 19:01
  • your code is a bit advanced for me, I can't edit it to show all levels with sums of children :/
    – Abeer Sul
    Commented Sep 6, 2020 at 20:06
  • 1
    i will make a new example, then you can see the changes
    – nbk
    Commented Sep 6, 2020 at 20:24
0

Based on the accepted answer from @nbk, I made a small change in the sql code to fit my case. I Hope this is useful for others:

-- HELPER SP 

DELIMITER //
DROP PROCEDURE IF EXISTS sumChildrenAccounts//
CREATE PROCEDURE sumChildrenAccounts(
  _Level SMALLINT
)
BEGIN
  DECLARE finished INTEGER DEFAULT 0;
  DECLARE _accoujntno INTEGER DEFAULT 0;
  DECLARE _uacn varchar(191) DEFAULT "";
    DEClARE curaccount CURSOR FOR 
            SELECT account_no ,user_account_number FROM VIEW2 WHERE length(user_account_number)-length(replace(user_account_number,'-',''))+1  = _Level ORDER BY user_account_number;

    -- declare NOT FOUND handler
    DECLARE CONTINUE HANDLER 
  FOR NOT FOUND SET finished = 1;
  
  CREATE TEMPORARY TABLE TOTALS_BY_LEVEL(
          user_account_number VARCHAR(191),
          `Debit Before Period`   DECIMAL(20,2),
          `Credit Before Period` DECIMAL(20,2),
          `Debit In Period`      DECIMAL(20,2),
          `Credit In Period`      DECIMAL(20,2)
  );
  OPEN curaccount;

  getaccount: LOOP
      FETCH curaccount INTO _accoujntno,_uacn;
      IF finished = 1 THEN 
          LEAVE getaccount;
      END IF;
      INSERT INTO TOTALS_BY_LEVEL SELECT _uacn ,SUM(`Debit Before Period`),SUM(`Credit Before Period`) ,SUM(`Debit In Period`) ,SUM(`Credit In Period`)  
      FROM VIEW2 
      WHERE LEFT(user_account_number,  (_level -1 + (_level * 3))) = _uacn;
    
  END LOOP getaccount;
    CLOSE curaccount;
  
  -- update parents' totals in the same source table (where parents had nulls actually)
  UPDATE TOTALS_BY_LEVEL b
    INNER JOIN VIEW2 a ON  b.user_account_number = a.user_account_number
    SET 
      a. `Debit Before Period`       = b. `Debit Before Period` ,
      a. `Credit Before Period`      = b. `Credit Before Period`,
      a. `Debit In Period`           = b. `Debit In Period`     ,
      a. `Credit In Period`          = b. `Credit In Period`    ;
  DROP TABLE IF EXISTS TOTALS_BY_LEVEL;

END//
DELIMITER ;

Then I called it in a loop inside the original stored procedure:

-- loop from the 1 until the deepest level of child accounts
SET @ml := 1;
SELECT max(level) FROM acc_accounts LIMIT 1 INTO @ml; 

SET @x = 1;
WHILE @x <= @ml DO
    call sumChildrenAccounts(@x);
    SET @x := @x + 1;
END WHILE;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.