I have some code drafted but I’m not sure how to finish it, or if it needs more work. It looks like this.
select p.product_id, p.product_name, pp.effective_date, pp.unit_price
from products p
inner join product_price pp
on p.product_id = pp.product_id
where ( .stuck here)
Everything looks good, but how do I get the price to be based on the given effective date? The given effective date is 01/01/2021. I was thinking something maybe like this for the where:
where effective_date = 01/01/2021;
I’m not sure if this is correct though. I tried running it and similar where statements but nothing came of it.
Sample data:
products
P_id, p_name
11 , boys shorts
product_price
p_id, eff_date , unit_price
11 , 01-JAN-21, 10.48
I want the product’s price to now be a calculation based on a given date, using a join between Products and Product_Price.
[
Advertisement
Answer
When price data is stored with only a single date, it typically means “use this price from this date onward, but only up to the next date_effective”.
The window function row_number()
assigns an integer to each row, within a related over clause
, partition by
controls what is used to re-start numbering at 1 and an order by
determines the sequence of rows and numbers within the partition. So by using a descending date order the most recent date per partition can be identified with a row number of 1.
If you couple this technique with a filter on the effective date being less than or equal to a given date, then the price that applies on the given date will be returned.:
select p.product_id, p.product_name, pp.effective_date, pp.unit_price
from products p
inner join (
select
product_price.*
, row_number() over(partition by product_id order by effective_date DESC) as rn
from product_price
where effective_date <= to_date('01/01/2021','dd/mm/yyyy')
) pp on p.product_id = pp.product_id
and pp.rn = 1 /* only the relevant date/price is returned */
The second join condition could be used as a where condition instead
select p.product_id, p.product_name, pp.effective_date, pp.unit_price
from products p
inner join (
select
product_price.*
, row_number() over(partition by product_id order by effective_date DESC) as rn
from product_price
where effective_date <= to_date('01/01/2021','dd/mm/yyyy')
) pp on p.product_id = pp.product_id
where pp.rn = 1 /* only the relevant date/price is returned */
Sample Data
CREATE TABLE PRODUCTS (
PRODUCT_ID INTEGER,
PRODUCT_NAME VARCHAR(100));
CREATE TABLE PRODUCT_PRICE (
PRODUCT_ID INTEGER,
EFFECTIVE_DATE DATE ,
UNIT_PRICE DECIMAL(12,3));
INSERT INTO PRODUCTS VALUES(100,'Product: 100');
INSERT INTO PRODUCTS VALUES(3412,'Product: 3412');
INSERT INTO PRODUCTS VALUES(1034,'Product: 1034');
INSERT INTO PRODUCTS VALUES(775522,'Product: 775522');
INSERT INTO PRODUCTS VALUES(101,'Product: 101');
INSERT INTO PRODUCTS VALUES(2342,'Product: 2342');
INSERT INTO PRODUCTS VALUES(8643,'Product: 8643');
INSERT INTO PRODUCTS VALUES(99771,'Product: 99771');
INSERT INTO PRODUCTS VALUES(2324,'Product: 2324');
INSERT INTO PRODUCTS VALUES(103,'Product: 102');
INSERT INTO PRODUCT_PRICE VALUES(100, TO_DATE('2020-09-01','YYYY-MM-DD'),10.12);
INSERT INTO PRODUCT_PRICE VALUES(101, TO_DATE('2020-09-01','YYYY-MM-DD'),10.12);
INSERT INTO PRODUCT_PRICE VALUES(103, TO_DATE('2020-09-01','YYYY-MM-DD'),10.12);
INSERT INTO PRODUCT_PRICE VALUES(1034, TO_DATE('2020-09-01','YYYY-MM-DD'),10.12);
INSERT INTO PRODUCT_PRICE VALUES(2342, TO_DATE('2020-09-01','YYYY-MM-DD'),10.12);
INSERT INTO PRODUCT_PRICE VALUES(3412, TO_DATE('2020-09-01','YYYY-MM-DD'),10.12);
INSERT INTO PRODUCT_PRICE VALUES(100, TO_DATE('2021-01-01','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(101, TO_DATE('2020-11-11','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(103, TO_DATE('2021-01-01','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(1034, TO_DATE('2020-11-11','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(2342, TO_DATE('2021-01-01','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(3412, TO_DATE('2020-12-01','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(8643, TO_DATE('2021-01-01','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(99771, TO_DATE('2021-02-01','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(2324, TO_DATE('2021-01-01','YYYY-MM-DD'),10.43);
INSERT INTO PRODUCT_PRICE VALUES(775522, TO_DATE('2021-03-01','YYYY-MM-DD'),10.43);
Results
+------------+---------------+----------------------+------------+
| PRODUCT_ID | PRODUCT_NAME | EFFECTIVE_DATE | UNIT_PRICE |
+------------+---------------+----------------------+------------+
| 100 | Product: 100 | 2021-01-01T00:00:00Z | 10.43 |
| 101 | Product: 101 | 2020-11-11T00:00:00Z | 10.43 |
| 103 | Product: 102 | 2021-01-01T00:00:00Z | 10.43 |
| 1034 | Product: 1034 | 2020-11-11T00:00:00Z | 10.43 |
| 2324 | Product: 2324 | 2021-01-01T00:00:00Z | 10.43 |
| 2342 | Product: 2342 | 2021-01-01T00:00:00Z | 10.43 |
| 3412 | Product: 3412 | 2020-12-01T00:00:00Z | 10.43 |
| 8643 | Product: 8643 | 2021-01-01T00:00:00Z | 10.43 |
+------------+---------------+----------------------+------------+
see this working demo at http://sqlfiddle.com/#!4/8a6c9/2