Jake Wagner
Jake Wagner

Reputation: 826

Running Total for Current & Previous Year on weekly basis

This query provides Year to date numbers for both Price and Square Feet of the current year and the previous year to date. This is more like the Running Total of the current Year and the Previous year with respect to the weeks in this case from 1 through 7 and so on..... (week 7th of 2017 ended on 02/19/2017) of the current year and the previous year(week 7th of 2016 ended on 02/22/2016). The reason why I am using subqueries is because this is the only way I know to get around this situation. And of course if you think there is a shorter, viable alternative of executing this query, please advice.

Actual_Sale_Date holds data on all of the seven days of the week but we cut off on Sunday that is why 2/22/2016 (Sunday ending 7th week of 2016) and 2/19/2017 (Sunday ending 7th week of 2017).

I tried "Actual_Sale_Date" = date_trunc('week', now())::date - 1 this function only returns the previous week data ending on the passed Sunday. I took a look at interval since dateadd does not exist in postgresql but could not get my ways around with it.

My query:

select (money(Sum("Price") / COUNT("Price"))) as "Avg_Value YTD",
Round(Avg("Price"/"Sq_Ft"),+2) as "Avg_PPSF YTD",

(select 
(money(Sum("Price") / COUNT("Price")))  from allsalesdata
where "Actual_Sale_Date" >=  '01/01/2016' AND "Actual_Sale_Date" < '02/22/2016'
and "Work_ID" = 'SO') AS "Last Year at this time Avg_Value", 


(select Round(Avg("Price"/"Sq_Ft"),+2)
from allsalesdata
where "Actual_Sale_Date" >=  '01/01/2016' AND "Actual_Sale_Date" <  '02/22/2016' 
and "Work_ID" = 'SO') AS "Last Year at this time Avg_PPSF"


from allsalesdata
where "Actual_Sale_Date" >=  '01/01/2017' AND "Actual_Sale_Date" <'02/20/2017'
and "Work_ID" = 'SO'

Sample Data:

Price       Sq_Ft        Actual_Sale_Date        Work_ID

45871       3583           01/15/2016             SO
55874       4457           02/05/2016             SO
88745       4788           02/20/2016             SO
58745       1459           01/10/2016             SO
88749       2145           01/25/2017             SO
74856       1478           01/25/2017             SO
74586       4587           01/31/2017             ABC
74745       1142           02/10/2017             SO
74589       2214           02/19/2017             SO

Upvotes: 1

Views: 828

Answers (1)

Patrick
Patrick

Reputation: 32374

This should be what you need (assuming you have a recent version of PG):

SELECT DISTINCT wk AS "Week",
       sum("Price")::money FILTER (WHERE yr = 2017) OVER w / 
       count("Price") FILTER (WHERE yr = 2017) OVER w AS "Avg_Value YTD",
       sum("Price")::money FILTER (WHERE yr = 2017) OVER w / 
       sum("Sq_Ft") FILTER (WHERE yr = 2017) OVER w AS "Avg_PPSF YTD",
       sum("Price")::money FILTER (WHERE yr = 2016) OVER w / 
       count("Price") FILTER (WHERE yr = 2016) OVER w AS "Last Year this time Avg_Value",
       sum("Price")::money FILTER (WHERE yr = 2016) OVER w / 
       sum("Sq_Ft") FILTER (WHERE yr = 2016) OVER w AS "Last Year this time Avg_PPSF",
FROM (
    SELECT extract(isoyear from "Actual_Sale_Date")::integer AS yr,
           extract(week from "Actual_Sale_Date")::integer AS wk,
           "Price", "Sq_Ft"
    FROM allsalesdata
    WHERE "Work_ID" = 'SO') sub
-- optional, show only completed weeks in this year:
WHERE wk <= extract(week from CURRENT_DATE)::integer - 1 
WINDOW w AS (ORDER BY wk)
ORDER BY wk;

In the inner query the year and week of the sale date are extracted for every sale. The week starts on Monday, as per your requirement.

In the main query these rows are processed as a single partition frame, i.e. from the start of the partition (= first row) to the last peer of the current row. Since the window definition orders the rows by wk, all rows from the start (week = 1) to the current week are included in the summarization. This will give you the running total. The sum() and count() functions filter by the year in question and the DISTINCT clause ensures that you get only a single row per week.

Upvotes: 2

Related Questions