Home > database >  BigQuery - Year over Year Comparison with Month to Date
BigQuery - Year over Year Comparison with Month to Date

Time:08-29

I am having trouble accurately doing a year over year comparison by month but at any point during the month. For example for August 2022 vs 2021, I want to compare August 1 to today, rather than full month of August 2021.

My data has a date field.

I want the final result to basically be:

Product_ID, Year, Month, PY_Sales, CY_Sales

I have daily totals. Some products do have not sales on certain days though. Here's an example:

product_id sale_date units
1 2021-01-01 5
2 2021-01-02 4
... ... ...
1 2021-06-05 2
2 2021-08-01 1
2 2021-08-31 6
2 2022-01-06 1
2 2022-08-15 9

The final result for August should be:

product_id Year Month PY_Sales CY_Sales
2 2022 8 1 9

Right now my code will show 7 for August for product_id = 2 because 6 sales happened on August 31st but that day hasn't happened yet in 2022.

This is the code I have, but it doesn't do MTD. Right now, PY_Sales for August 2022 is showing the entire August of 2021, but I want it to show the MTD of August 2021. I used this code because some products do not have sales on certain months.

    WITH cte AS 
(
SELECT 
     PRODUCT_ID,
     EXTRACT(YEAR FROM SALE_DATE) AS Year,
     EXTRACT(MONTH FROM SALE_DATE) AS Month,
     CONCAT(EXTRACT(YEAR FROM SALE_DATE), '-',EXTRACT(MONTH FROM SALE_DATE)) AS Year_Month,
     SUM(Units) AS Units
FROM data
WHERE Product_ID = 1
AND DATE(SALE_DATE) >= '2019-01-01'
GROUP BY 1, 2, 3
),

    diff AS 
( 
SELECT 
     COALESCE(c.PRODUCT_ID, p.PRODUCT_ID) AS Product_ID,
     COALESCE(c.Year, p.Year   1) AS Year,
     COALESCE(c.Month, p.Month) AS Month,
     IFNULL(c.Units, 0) AS Current_Units,
     IFNULL(p.Units, 0) AS Previous_Units,
     NULLIF(((IFNULL(c.Units, 0) - IFNULL(p.Units,0)) / p.Units),0) * 100 AS Percent_Change
FROM CTE c
FULL OUTER JOIN CTE p ON c.PRODUCT_ID = p.PRODUCT_ID AND c.Year = p.Year   1 AND c.Month = p.Month
WHERE c.Year <= EXTRACT(YEAR FROM CURRENT_DATE())
ORDER BY 2, c.Year, c.Month
)
SELECT *
FROM diff
--This is to avoid dividing by 0
WHERE diff.Previous_Units > 0
--AND Percent_Change <= -.5

I'm being a little repetitive but I hope this is clear! Thank you so much!

CodePudding user response:

In the cte table you summarize the sold units by month and year. Your question can be solved by adding here a column units_last_year. This contains the units, which are sold up to the day one year ago. Today is the 27th of August 2022, therefore the units on the 31th of August 2021 will be set to zero.

SUM(Units) AS Units,
SUM(IF(SALE_DATE< date_sub(current_Date(),interval 1 year), Units, 0 )) as units_last_year

Please use the safe_divide command, if there is any chance of diving by zero

Here is the full query with example data. You given an example of fixed dates, which are compared to the current date. Therefore, the query would not show the desired effect after 30th of August 2022. The product_id three is made up values related to the current date, thus the following query yields results after August 2022.

with data as (

select *,date(sale_date_) as sale_date
from (
Select 1 product_id,    "2021-01-01" sale_date_,    5 units
union all select 2,"2021-01-02",    4
union all select 1,"2021-06-05",    2
union all select 2,"2021-08-01",    1
union all select 2,"2021-08-31",    6
union all select 2,"2022-01-06",    1
union all select 2,"2022-08-15",    9
union all select 3, current_date(), 10
union all select 3, date_sub(current_date(),interval 1 year), 9
union all select 3, date_sub( date_trunc(current_date(),month),interval 1 year), 1
)
),
cte AS 
(
SELECT 
     PRODUCT_ID,
     EXTRACT(YEAR FROM SALE_DATE) AS Year,
     EXTRACT(MONTH FROM SALE_DATE) AS Month,
     CONCAT(EXTRACT(YEAR FROM SALE_DATE), '-',EXTRACT(MONTH FROM SALE_DATE)) AS Year_Month,
     SUM(Units) AS Units,
     sum(if(SALE_DATE< date_sub(current_Date(),interval 1 year), units, 0 )) as units_last_year
FROM data
WHERE # Product_ID = 1 AND 
DATE(SALE_DATE) >= '2019-01-01'
GROUP BY 1, 2, 3, 4
),

    diff AS 
( 
SELECT 
     COALESCE(c.PRODUCT_ID, p.PRODUCT_ID) AS Product_ID,
     COALESCE(c.Year, p.Year   1) AS Year,
     COALESCE(c.Month, p.Month) AS Month,
     IFNULL(c.Units, 0) AS Current_Units,
     IFNULL(p.Units, 0) AS Previous_Units,
     IFNULL(p.Units_last_Year, 0) AS Previous_Units_ok,
     NULLIF(((IFNULL(c.Units, 0) - IFNULL(p.Units,0)) / p.Units),0) * 100 AS Percent_Change,
     NULLIF(safe_divide((IFNULL(c.Units, 0) - IFNULL(p.Units_last_Year,0)) , p.Units_last_Year),0) * 100 AS Percent_Change_ok,
FROM CTE c
FULL OUTER JOIN CTE p ON c.PRODUCT_ID = p.PRODUCT_ID AND c.Year = p.Year   1 AND c.Month = p.Month
WHERE c.Year <= EXTRACT(YEAR FROM CURRENT_DATE())
ORDER BY 2, c.Year, c.Month
)
SELECT *
FROM diff

  • Related