简体   繁体   中英

Window functions to calculate MTD metrics

I am trying to create a query that would calculate a number of metrics MTD. So if I wanted to calculate revenue on December 12th, then it would sum all days between dec 1st and December 12th.

If I wanted to compare revenue growth between two months then it would compare that interval with nov 1st to nov 12th.

I have been trying to use window functions to do exactly this.

select ms.date, ms.market, 
sum(ms.rev) as "rev_this_month",
lag(sum(ms.rev)) over (partition by ms.market order by ms.date) as "last_month_rev",

(sum(ms.rev) - (cast((lag(sum(ms.rev)) over 
(partition by ms.market order by ms.date))as float)))/ 
cast((lag(sum(ms.rev)) over 
(partition by ms.market order by ms.date))as float) as "MTD_rev_growth"

From market_sales ms

where 
a.date between trunc(DATE_TRUNC('day', current_date)) - interval '30 day'
 and trunc(DATE_TRUNC('day', current_date))

And I would expect something like this:

Date       | Market | Rev_this_month | Rev_last_month | MTD
2018-12-12     Aus         10                5                1.0
2018-12-12     SF          40               40                 0
2018-12-12     PA          10               20               -0.50

But instead, I get

Date       | Market | Rev_this_month | Rev_last_month | MTD_Rev_growth
2018-12-12     Aus         10                5                1.0
2018-12-11     Aus         5                 2                 x
2018-12-10     Aus         2                 0                 x
...
2018-12-12     SF         40                 40                0
2018-12-11     SF         40                 20               1.0

and so on.

Is it related to my window functions or is it how I am filtering things in my where clause?

Would appreciate any help.

EDIT:

Apologies for getting back late, Went camping. Anyway here is some sample data based on request:

Market | Date        | Rev
Aus      2018-01-03    55
SF       2018-01-04    33
SF       2018-01-20    04
PA       2018-01-21    60
BAL      2018-01-29    70
SF       2018-02-12    31

Based on your description and shown expected results, you only ever want to compare the current month so far, to the same number of days last month...

WITH
  data_window AS
(
  SELECT
    *,
    CASE WHEN market_sales.date >= DATE_TRUNC('month', CURRENT_DATE) THEN 1 ELSE 0 END   AS is_this_month
  FROM
    market_sales
  WHERE
        market_sales.date >= DATEADD('month', -1, DATE_TRUNC('month', CURRENT_DATE))
    AND DATE_PART('day', market_sales.date) <= DATE_PART('day', CURRENT_DATE)
)
SELECT
  CURRENT_DATE   AS date,
  market,
  SUM(CASE WHEN is _this_month = 1 THEN rev ELSE 0 END)  AS rev_this_month,
  SUM(CASE WHEN is _this_month = 0 THEN rev ELSE 0 END)  AS rev_last_month,
  CAST(SUM(CASE WHEN is _this_month = 1 THEN rev ELSE 0 END) AS FLOAT)
  /
  SUM(CASE WHEN is _this_month = 0 THEN rev ELSE 0 END)
  - 1.0
                                                         AS mtd_rev_growth
FROM
  data_window
GROUP BY
  market

I know nothing about amazon-redshift, but going for the sql, check if you can include this additional column in the select:

row_number() OVER (PARTITION BY ms.market ORDER BY ms.date) as rownumber

Then you select from your query, like this:

SELECT *
FROM
(
  -- your select here...
)
WHERE 1=1
  AND rownumber = 1
;

Hope it helps.

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