Reputation: 55
I'm experimenting with the Adventureworks database in psql, and I wanted to try and select peak monthly sales over the years available in the database. So far, my query is the following:
WITH ranked_monthly_sales AS (
SELECT
RANK() OVER (PARTITION BY
to_char(soh.orderdate, 'MM')
ORDER BY SUM(sod.unitprice) DESC
) AS rank,
to_char(soh.orderdate, 'MM') AS order_month,
to_char(soh.orderdate, 'YYYY') AS order_year,
SUM(sod.unitprice) AS unit_price
FROM
sales.salesorderheader soh
INNER JOIN sales.salesorderdetail sod
ON soh.salesorderid = sod.salesorderid
GROUP BY
order_month,
order_year
ORDER BY
order_year,
order_month
)
SELECT *
FROM ranked_monthly_sales
WHERE rank = 1
ORDER BY rank, order_year, order_month, order_year;
This returns the following result:
rank order_month order_year unit_price
1 6 2013 2148488.3562
1 7 2013 2139025.3667
1 8 2013 1736638.0688
1 9 2013 2197327.4224
1 10 2013 2534203.6808
1 11 2013 2245166.9681
1 12 2013 2367052.5368
1 1 2014 2607573.234
1 2 2014 1336516.3606
1 3 2014 3489718.7278
1 4 2014 1796448.3395
1 5 2014 3172559.0484
However, I'm trying to get something akin to what I created in Tableau, using this calculated field:
IF
SUM([unit_price]) > LOOKUP(SUM([unit_price]),-1)
AND
SUM([unit_price]) > LOOKUP(SUM([unit_price]),1)
THEN
'Peak'
END
Using this field as a filter gives me wildly different results, as shown in this table:
Month of order_date Peaks unit_price
December 2012 Peak 1,257,847.1714
August 2011 Peak 1,263,165.3553
September 2012 Peak 1,367,601.4629
March 2013 Peak 1,454,903.3623
March 2012 Peak 1,553,199.7152
June 2012 Peak 1,602,987.706
January 2012 Peak 1,955,076.8224
October 2011 Peak 1,983,602.0312
June 2013 Peak 2,148,488.3562
October 2013 Peak 2,534,203.6808
January 2014 Peak 2,607,573.234
May 2014 Peak 3,172,559.0484
March 2014 Peak 3,489,718.7278
Can someone help me fix my query to get what I am looking for?
Much appreciated.
Upvotes: 1
Views: 150
Reputation: 1269823
If you want monthly sales that are larger than the previous month or the next month, then use lead()
/lag()
:
WITH monthly_sales AS (
SELECT to_char(soh.orderdate, 'YYYY-MM') AS yyyymm,
SUM(sod.unitprice) AS sales
FROM sales.salesorderheader soh INNER JOIN
sales.salesorderdetail sod
ON soh.salesorderid = sod.salesorderid
GROUP BY to_char(soh.orderdate, 'YYYY-MM')
)
SELECT *
FROM (SELECT ms.*,
LAG(sales) OVER (ORDER BY yyyymm) as prev_sales,
LEAD(sales) OVER (ORDER BY yyyymm) as next_sales,
FROM monthly_sales ms
) ms
WHERE sales > prev_sales AND sales > next_sales
Upvotes: 1