I need to do something really weird, which is to create fake records in a view to fill the gap between posted dates of product prices.
Actually, my scenario is a little bit more complicated than that, but I've simplified to products/dates/prices.
Let's say we have this table:
create table PRICES_TEST
(
PRICE_DATE date not null,
PRODUCT varchar2(13) not null,
PRICE number
);
alter table PRICES_TEST
add constraint PRICES_TEST_PK
primary key (PRICE_DATE, PRODUCT);
With these records:
insert into PRICES_TEST values (date'2012-04-15', 'Screw Driver', 13);
insert into PRICES_TEST values (date'2012-04-18', 'Screw Driver', 15);
insert into PRICES_TEST values (date'2012-04-13', 'Hammer', 10);
insert into PRICES_TEST values (date'2012-04-16', 'Hammer', 15);
insert into PRICES_TEST values (date'2012-04-19', 'Hammer', 17);
selecting records will return me this:
PRICE_DATE PRODUCT PRICE
------------------------- ------------- ----------------------
13-Apr-2012 00:00:00 Hammer 10
16-Apr-2012 00:00:00 Hammer 15
19-Apr-2012 00:00:00 Hammer 17
15-Apr-2012 00:00:00 Screw Driver 13
18-Apr-2012 00:00:00 Screw Driver 15
Assuming today is Apr 21 2012, I need a view that shall repeat each price every day until a new price is posted. Like this:
PRICE_DATE PRODUCT PRICE
------------------------- ------------- ----------------------
13-Apr-2012 00:00:00 Hammer 10
14-Apr-2012 00:00:00 Hammer 10
15-Apr-2012 00:00:00 Hammer 10
16-Apr-2012 00:00:00 Hammer 15
17-Apr-2012 00:00:00 Hammer 15
18-Apr-2012 00:00:00 Hammer 15
19-Apr-2012 00:00:00 Hammer 17
20-Apr-2012 00:00:00 Hammer 17
21-Apr-2012 00:00:00 Hammer 17
15-Apr-2012 00:00:00 Screw Driver 13
16-Apr-2012 00:00:00 Screw Driver 13
17-Apr-2012 00:00:00 Screw Driver 13
18-Apr-2012 00:00:00 Screw Driver 15
19-Apr-2012 00:00:00 Screw Driver 15
20-Apr-2012 00:00:00 Screw Driver 15
21-Apr-2012 00:00:00 Screw Driver 15
Any ideas how to do that? I cannot really use other auxiliary tables, triggers nor PL/SQL programming, I really need to do this using a view.
I think this can be done using oracle analytics, but I'm not familiar with that. I tried to read this http://www.club-oracle.com/articles/analytic-functions-i-introduction-164/ but I didn't get it at all.
You can create a row generator statement using the CONNECT BY LEVEL
syntax, cross joined with the distinct products in your table, and then outer join that to your prices table. The final touch is to use the LAST_VALUE
function and IGNORE NULLS
to repeat the price until a new value is encountered, and since you wanted a view, with a CREATE VIEW
statement:
create view dense_prices_test as
select
dp.price_date
, dp.product
, last_value(pt.price ignore nulls) over (order by dp.product, dp.price_date) price
from (
-- Cross join with the distinct product set in prices_test
select d.price_date, p.product
from (
-- Row generator to list all dates from first date in prices_test to today
with dates as (select min(price_date) beg_date, sysdate end_date from prices_test)
select dates.beg_date + level - 1 price_date
from dual
cross join dates
connect by level <= dates.end_date - dates.beg_date + 1
) d
cross join (select distinct product from prices_test) p
) dp
left outer join prices_test pt on pt.price_date = dp.price_date and pt.product = dp.product;
I think I have a solution using an incremental approach toward the final result with CTE's:
with mindate as
(
select min(price_date) as mindate from PRICES_TEST
)
,dates as
(
select mindate.mindate + row_number() over (order by 1) - 1 as thedate from mindate,
dual d connect by level <= floor(SYSDATE - mindate.mindate) + 1
)
,productdates as
(
select p.product, d.thedate
from (select distinct product from PRICES_TEST) p, dates d
)
,ranges as
(
select
pd.product,
pd.thedate,
(select max(PRICE_DATE) from PRICES_TEST p2
where p2.product = pd.product and p2.PRICE_DATE <= pd.thedate) as mindate
from productdates pd
)
select
r.thedate,
r.product,
p.price
from ranges r
inner join PRICES_TEST p on r.mindate = p.price_date and r.product = p.product
order by r.product, r.thedate
mindate
retrieves the earliest possible date in the data setdates
generates a calendar of dates from earliest possible date to today.productdates
cross joins all possible products with all possible datesranges
determines which price date applied at each dateinner join
conditionDemo: http://www.sqlfiddle.com/#!4/e528f/126
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With