Search code examples
sqlfirebirdcycleseries

Cycle in SQL query?


I have query, where I call function StoreFlowsByDates

select
  sum(a.beglocalamount+a.localamount)
from
 StoreFlowsByDates(ib_encodedate(EXTRACT(YEAR FROM CURRENT_DATE),1 ,1), ib_encodedate(EXTRACT(YEAR FROM CURRENT_DATE), 12 ,31), '', '', '', '', '', '', '', 'N', 'N', 'N', 'N', '1000000101', '') a

This function return values in selected period. And I need to edit this query to return value for each month in year. Something like:

select
  sum(a.beglocalamount+a.localamount),
  [SELECTED_MONTH]
from
 StoreFlowsByDates(ib_encodedate(EXTRACT(YEAR FROM CURRENT_DATE),[SELECTED_MONTH] ,1), ib_encodedate(EXTRACT(YEAR FROM CURRENT_DATE), [SELECTED_MONTH] ,31), '', '', '', '', '', '', '', 'N', 'N', 'N', 'N', '1000000101', '') a
group by
[SELECTED_MONTH]

but in cycle from 1 to 12. It's something like this even possible?


Solution

  • You don't need a loop, but a simple series of integers against which you can JOIN.

    Table of integers

    In SQL, a table of integers is often used for this. E.g.,

    CREATE TABLE UTIL$KILO (i INTEGER NOT NULL); -- one thousand integers, 0 – 999
    INSERT INTO UTIL$KILO (i) VALUES (0);
    INSERT INTO UTIL$KILO (i) VALUES (1);
    ...
    INSERT INTO UTIL$KILO (i) VALUES (999);
    

    Your series is so small that you could plausibly make such a result set inline:

        SELECT SUM(...),
               i AS "MONTH"
          FROM (SELECT 1 AS i        --
                  UNION ALL          -- We'll just enumerate the months here
                SELECT 2             --
                  UNION ALL          --
                ...                  --
                SELECT 12) month_nos
    CROSS JOIN StoreFlowsByDates(ib_encodedate(..., i, ...)...)
      GROUP BY 2;
    

    Series-generating procedures

    Some RDBMS supply functions to generate such series, and a Firebird selectable stored procedure could be written for the same effect:

    -- UTIL$RANGE(start, stop, step)
    --
    -- Firebird selectable stored procedure for producing integer ranges.
    -- (Public Domain)
    --
    CREATE EXCEPTION util$err_range_zero_step 'step size may not be zero';
    SET TERM !!;
    CREATE PROCEDURE util$range("Start" INTEGER, "Stop" INTEGER, "Step" INTEGER)
      RETURNS (i INTEGER) AS
    BEGIN
      IF ("Step" > 0) THEN BEGIN
        i = "Start";
        WHILE (i <= "Stop") DO BEGIN
          SUSPEND;
          i = i + "Step";
        END
      END
      ELSE IF ("Step" < 0) THEN BEGIN
        i = "Start";
        WHILE (i >= "Stop") DO
        BEGIN
          SUSPEND;
          i = i + "Step";
        END
      END
      ELSE IF ("Step" = 0) THEN
        EXCEPTION util$err_range_zero_step;
      -- ELSE return empty set
    END !!
    SET TERM ;!!
    

    The query then looks like this:

        SELECT SUM(...),
               i AS "MONTH"
          FROM util$range(1, 12, 1)
    CROSS JOIN StoreFlowsByDates(ib_encodedate(..., i, ...)...)
      GROUP BY 2;