В данных вашего примера цены только растут. Если это так, самый простой метод - это совокупный минимум:
select t.*,
min(current_date) over (partition by product_id, price) as changed_date
from t;
Если это не так, особенно если цены могут вернуться к предыдущим ценам, у вас есть пробелы и острова проблема. Самым простым решением в этом случае, вероятно, является разница номеров строк:
select t.*,
min(date) over (partition by product_id, price, (seqnum - seqnum_2)) as change_date
from (select t.*,
row_number() over (partition by product_id order by current_date) as seqnum,
row_number() over (partition by product_id, price order by current_date) as seqnum_2
from t
) t;
Почему эту работу объяснить немного сложно. Но если вы посмотрите на результаты подзапроса, вы увидите, как разница в номерах строк идентифицирует соседние строки с одинаковой ценой.