Home > Back-end >  Finding anomalies in the product prices
Finding anomalies in the product prices

Time:05-23

I was given a SQL problem that has me stumped and was wondering if someone can shed some light on the best way to do this.

QUESTION: Given the table "product_price" represents average price for a product for a period of time. All days from the range occur in the "day" column, which is NOT sorted.

day Price ($)
4 2
5 1
3 1
1 1
2 5

Find anomalies in the product prices during this time period, more specifically find days when the price spiked (days on which the price was strictly larger than on the day before and the day after).

The first and last days can never be spikes.

EXPECTED OUTCOME: Output should be ordered in increasing order by "day"

day
2
4

QUERY: I have tired this query

SELECT day FROM (
    SELECT
        day
        ,prev_price - price AS pre_diff
        ,price - next_price AS next_diff
    FROM (
        SELECT 
            day
            ,price
            ,LEAD(price) OVER(price) AS prev_price
            ,LAG(price) OVER(price) AS next_price
        FROM product_price
        ORDER BY day ASC
    ) a
) b
WHERE pre_diff > 1 and next_diff > 1
ORDER by day;

UPDATE: I think I solved it. Thanks @hsnsd for the tip. Would still appreciate any input if there is a better way to write this query.

SELECT day FROM (
    SELECT
        day
        ,price
        ,prev_price
        ,next_price
        ,price - prev_price AS pre_diff
        ,next_price - price AS next_diff
    FROM (
        SELECT 
            day
            ,price
            ,COALESCE(LAG(price) OVER(ORDER BY day ASC),0) AS prev_price
            ,COALESCE(LEAD(price) OVER(ORDER BY day ASC),0) AS next_price
        FROM prices
    ) a
) b
WHERE (day NOT IN (SELECT MIN(day) FROM  prices) AND
day NOT IN (SELECT MAX(day) FROM  prices))
AND (pre_diff > 0 AND  next_diff < 0)
ORDER BY "day";

enter image description here

CodePudding user response:

It looks like the following should give you the desired result:

with s as (
  select *, 
    Lag(Price, 1, Price) over(order by day) p,
    Lead(Price, 1, Price) over(order by day) n
  from prices
)
select day
from s
where p < Price and n < Price;
  • Related