Numeri in corsa

I numeri progressivi sono, in parole povere, quando i numeri vengono sommati l'uno all'altro. Ad esempio, si vogliono conoscere i valori anno per anno (YTD). La somma di numeri è forse un caso spesso utilizzato, ma le possibilità non sono limitate a questo. Si può anche fare una media mobile.

In questo caso lavoreremo con un esempio di YTD. Supponiamo di avere una tabella con le entrate di una certa categoria per mese.

ea_month    id       amount    ea_year    circle_id
April       92570    1000      2014        1
April       92571    3000      2014        2
April       92572    2000      2014        3
March       92573    3000      2014        1
March       92574    2500      2014        2
March       92575    3750      2014        3
February    92576    2000      2014        1
February    92577    2500      2014        2
February    92578    1450      2014        3   

Per ottenere il totale del mese fino a quel momento, si potrebbe essere tentati di utilizzare una subquery come get all the amount of the previous months of the current year of my product. In realtà funziona, ma per ogni riga recuperata viene eseguita una sottoquery. Il che può facilmente portare a migliaia di query e quindi a tempi lunghi, come in questo esempio:

select branch_id,
       net_profit as store_profit,
       (select sum(net_profit) from store_sales as s2 where s2.city = s1.city) as city_profit,
       store_profit / city_profit * 100 as store_percentage_of_city_profit
    from store_sales as s1
    order by branch_id;
+-----------+--------------+-------------+---------------------------------+
| BRANCH_ID | STORE_PROFIT | CITY_PROFIT | STORE_PERCENTAGE_OF_CITY_PROFIT |
|-----------+--------------+-------------+---------------------------------|
|         1 |     10000.00 |    25000.00 |                     40.00000000 |
|         2 |     15000.00 |    25000.00 |                     60.00000000 |
|         3 |     10000.00 |    19000.00 |                     52.63157900 |
|         4 |      9000.00 |    19000.00 |                     47.36842100 |
+-----------+--------------+-------------+---------------------------------+

Postgres fornisce una cosiddetta funzione finestra chiamata OVER. Quindi, in un linguaggio meno naturale, si dice in SQL che si vuole avere una somma() su un set di dati PARZIALIZZATO per tempo e/o prodotto.

SELECT ea_month, id, amount, ea_year, circle_id
     , sum(amount) OVER (PARTITION BY circle_id
                         ORDER BY ea_year, ea_month) AS cum_amt
FROM   tbl
ORDER  BY circle_id, month;

Per avere effettivamente un YTD l'anno deve far parte del PARTIZIONAMENTO, altrimenti sarà su tutto il tempo.

Il calcolo verrà eseguito per riga. Quindi, se la tabella ha dati giornalieri, ma l'output è desiderato su base mensile, i dati devono essere prima raggruppati e sommati per mese, prima che un ytd su base mensile possa funzionare.