Home > database >  Calculate the period of validity of the price
Calculate the period of validity of the price

Time:01-23

I have a table with an item, its cost and the date it was added.

CREATE TABLE item_prices (
    item_id         INT,
    item_name       VARCHAR(30),
    item_price      DECIMAL(12, 2),
    created_dttm    DATETIME
);

INSERT INTO item_prices(item_id, item_name, item_price, created_dttm) VALUES
(1, 'spoon', 10.20 , '2023-01-01 01:00:00'),
(1, 'spoon', 10.20 , '2023-01-08 01:35:00'),
(1, 'spoon', 10.35 , '2023-01-14 15:00:00'),
(2, 'table', 40.00 , '2023-01-01 01:00:00'),
(2, 'table', 40.00 , '2023-01-03 11:22:00'),
(2, 'table', 41.00 , '2023-01-10 08:28:22'),
(1, 'spoon', 10.35 , '2023-01-28 21:52:00'),
(1, 'spoon', 11.00 , '2023-02-15 16:36:00'),
(2, 'table', 41.00 , '2023-02-16 21:42:11'),
(2, 'table', 45.20 , '2023-02-19 20:25:25'),
(1, 'spoon',  9.00 , '2023-03-02 14:50:00'),
(1, 'spoon',  9.00 , '2023-03-06 16:36:00'),
(1, 'spoon',  8.50 , '2023-03-15 12:00:00'),
(2, 'table', 30    , '2023-03-05 10:10:10'),
(2, 'table', 30    , '2023-03-10 15:45:00');

I need to create a new table with the following fields:

  • "item_id",
  • "item_name",
  • "item_price",
  • "valid_from_dt": date on which the price was effective (created_dttm price record)
  • "valid_to_dt": date until which this price was valid (created_dttm of the next record for this product "minus" one day)

I thought it might be possible to start by selecting days on which new entries are added with new prices with such a request:

SELECT item_id, item_name, item_price, 
       MIN(created_dttm) as dt 
FROM table
GROUP BY item_price, item_id, item_name

that provides me this output:

my aggregating

The expected output is the following:

item_id item_name item_price valid_from_dt valid_to_dt
1 spoon 10.20 2023-01-01 2023-01-13
1 spoon 10.35 2023-01-14 2023-02-14
1 spoon 11.00 2023-02-15 2023-03-01
1 spoon 9.00 2023-03-02 2023-03-01
1 spoon 8.50 2023-03-15 2023-03-14
2 table 40.00 2023-01-01 2022-01-09
2 table 41.00 2023-01-10 2023-02-18
.... .... .... .... ....

CodePudding user response:

select distinct
   item_id,
   item_name,
   first_value(item_price) over (partition by item_id order by created_dttm) as item_price, 
   min(created_dttm) over (partition by item_id ) as valid_from_dt,
   max(created_dttm) over (partition by item_id ) as valid_to_dt
from item_prices
;

output:

item_id item_name item_price valid_from_dt valid_to_dt
1 spoon 10.20 2023-01-01 01:00:00 2023-03-15 12:00:00
2 table 40.00 2023-01-01 01:00:00 2023-03-10 15:45:00

see: DBFIDDLE

CodePudding user response:

Your query is correct. It's only missing the next step:

  • retrieving the next "valid_from_dt" in the partition <item_id, item_name>, using the LEAD function
  • subtract 1 day from it
WITH cte AS (
    SELECT item_id, item_name, item_price, 
           MIN(created_dttm) AS valid_from_dt
    FROM item_prices
    GROUP BY item_id, item_name, item_price
)
SELECT *, 
       LEAD(valid_from_dt) OVER(PARTITION BY item_id, item_name) - INTERVAL 1 DAY AS valid_to_dt 
FROM cte

Check the demo here.

  • Related