简体   繁体   中英

Stored Procedure to create cumulative sums

I'm trying to write Firebird stored procedure, which returns me cumulative sums for twelve months grouped by another two fields. For now I created something like this:

SET TERM ^ ;

CREATE PROCEDURE A_OBRATZISKKUM(
  START_YEAR INTEGER,
  END_YEAR INTEGER)
RETURNS(
  OBRAT DOUBLE PRECISION,
  MESIC INTEGER,
  ROK INTEGER,
  SECURITYUSER_ID TYPE OF ID COLLATE WIN1250,
  FIRM_ID TYPE OF ID COLLATE WIN1250)
AS
DECLARE VARIABLE act_month INTEGER = 1;
begin
    for select
        sum(AO.Obrat), :act_MONTH, :start_YEAR, AO.SecurityUser_ID,
            AO.Firm_ID
    from A_OBRATYKUMHIST_TEMP AO
    where
        AO.Rok = :start_year
        and AO.Mesic <= :act_month
    group by
        AO.SecurityUser_ID, AO.Firm_ID
    into :obrat, :mesic, :rok, :securityuser_id, :firm_id
    do
    act_month = :act_MONTH + 1;
    suspend;
end^

SET TERM ; ^

But when I run it I get only one row with weird sum. What's wrong on my code?

EDIT1. I come out from this sql query:

select
        sum(AO.Obrat), *1*, 2012, AO.SecurityUser_ID,
            AO.Firm_ID
    from A_OBRATYKUMHIST_TEMP AO
    where
        AO.Rok = 2012
        and AO.Mesic <= *1*
    group by
        AO.SecurityUser_ID, AO.Firm_ID

When I take for example month number 3, I get sum of all previous months grouped by securityuser_id and firm_id . But if I want to get sums for all months, then I have to run this twelve times with replacing 1 for 2 , then for 3 , then ........ At the end I get cumulative sums splits up to months, years, users and firms.

A DO is followed by either a single statement, or by a block. You are currently doing a single SUSPEND instead of multiple suspends as your intention is. Instead of

FOR SELECT ...
DO
   statement;
SUSPEND;

You need to do

FOR SELECT ...
DO
BEGIN
   statement;
   SUSPEND;
END

Also the statement act_month = :act_MONTH + 1; should be act_month = act_MONTH + 1; (no colon : )

The running sum

The running sum can be achieved by self-joining for all months <= the current month and summing over that:

SELECT SUM(AO2.Obrat), AO.Mesic, AO.Rok, AO.SecurityUser_ID, AO.Firm_ID
FROM A_OBRATYKUMHIST_TEMP AO
INNER JOIN A_OBRATYKUMHIST_TEMP AO2
    ON AO2.Rok = AO.Rok AND AO2.Mesic <= AO.Mesic
WHERE AO.Rok = 2012
GROUP BY AO.Mesic, AO.Rok, AO.SecurityUser_ID, AO.Firm_ID

Note this only works within the same year, you'd need to modify the join condition if you need to sum over multiple years.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM