XXA
- table which contains price for items based on date range.
XXB
- table has new price for items based on date range.
Now I want XXA
table to be updated based on new prices from XXB
table considering date range.
If some dates are missing in new XXB
table then for those dates old data should be maintained in XXA
.
For example:
Table XXA
contents:
ITEM | PRICE | START_DATE | END_DATE
---------------------------------------
plug | 12 | 10-Jan-15 | 15-Jan-15
plug | 1 | 20-Jan-15 | 25-Jan-15
plug | 3 | 30-Jan-15 | 4-Feb-15
plug | 4 | 5-Feb-15 | 10-Feb-15
plug | 43 | 20-Feb-15 | 25-Feb-15
Table XXB
contents:
ITEM | PRICE | START_DATE | END_DATE
---------------------------------------
plug | 345 | 1-Jan-15 | 10-Jan-15
plug | 133 | 12-Jan-15 | 20-Jan-15
plug | 344 | 27-Jan-15 | 3-Feb-15
plug | 455 | 7-Feb-15 | 10-Feb-15
plug | 431 | 17-Feb-15 | 23-Feb-15
Now based on XXB
data, XXA
table should be changed like below, where the new price from XXA
table is updated for available date ranges, for other dates old price in XXA
is considered.
ITEM | PRICE | START_DATE | END_DATE
---------------------------------------
plug | 345 | 1-Jan-15 | 10-Jan-15
plug | 12 | 11-Jan-15 | 11-Jan-15
plug | 133 | 12-Jan-15 | 20-Jan-15
plug | 1 | 21-Jan-15 | 25-Jan-15
plug | 344 | 27-Jan-15 | 3-Feb-15
plug | 3 | 4-Feb-15 | 4-Feb-15
plug | 4 | 5-Feb-15 | 6-Feb-15
plug | 455 | 7-Feb-15 | 10-Feb-15
plug | 431 | 17-Feb-15 | 23-Feb-15
plug | 43 | 24-Feb-15 | 25-Feb-15
NOTE: I suppose, Only if we bring the output in single sql query we can use it to update the table XXA
accordingly. When i tried by taking individual scenario wise result goes wrong when data changes. Can somebody help me bring above output in single query.
Below is the code which i tried scenario wise:
with date_range as (select least(xa.min_start_date, xb.min_start_date) range_start,
greatest(xa.max_end_date, xb.max_end_date) range_end
from (select min(start_date) min_start_date,
max(end_date) max_end_date
from xxa) xa
cross join
(select min(start_date) min_start_date,
max(end_date) max_end_date
from xxb) xb),
dates as (select range_start + level -1 dt
from date_range
connect by range_start + level -1 <= range_end),
pivot_xxa as (select xxa.item,
xxa.price,
dts.dt,
'Exist' status
from xxa
inner join dates dts on (dts.dt between xxa.start_date and xxa.end_date)),
pivot_xxb as (select xxb.item,
xxb.price,
dts.dt,
'New' status
from xxb
inner join dates dts on (dts.dt between xxb.start_date and xxb.end_date)),
res as (select coalesce(pxb.item, pxa.item) item,
coalesce(pxb.price, pxa.price) price,
coalesce(pxa.dt, pxb.dt) dt,
row_number() over (partition by coalesce(pxb.item, pxa.item) order by coalesce(pxa.dt, pxb.dt))
- row_number() over (partition by coalesce(pxb.item, pxa.item), coalesce(pxb.price, pxa.price),pxa.status,pxb.status order by coalesce(pxa.dt, pxb.dt)) grp
from pivot_xxa pxa
full outer join pivot_xxb pxb on (pxa.item = pxb.item
and pxa.dt = pxb.dt))
select item,
price,
min(dt) start_date,
max(dt) end_date
from res
group by item,
price,
grp;
答案 0 :(得分:1)
这是一种方法,虽然它需要创建一个全局临时表,因为我无法解决如何将行合并回xxa(临时脑屁,或者真的不可行;我&#39;我不确定!开放给想法* {:-))。无论如何,除了作为下面插入/删除语句的包装器之外,不需要PL / SQL。
create table xxa (item varchar2(5),
price number,
start_date date,
end_date date);
create table xxb (item varchar2(5),
price number,
start_date date,
end_date date);
create global temporary table xxa_xxb_tmp_res (item varchar2(5),
price number,
start_date date,
end_date date);
insert into xxa
select 'plug', 12, to_date('10/01/2015', 'dd/mm/yyyy'), to_date('15/01/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 1, to_date('20/01/2015', 'dd/mm/yyyy'), to_date('25/01/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 3, to_date('30/01/2015', 'dd/mm/yyyy'), to_date('04/02/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 4, to_date('05/02/2015', 'dd/mm/yyyy'), to_date('10/02/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 43, to_date('20/02/2015', 'dd/mm/yyyy'), to_date('25/02/2015', 'dd/mm/yyyy') from dual;
insert into xxb
select 'plug', 345, to_date('01/01/2015', 'dd/mm/yyyy'), to_date('10/01/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 133, to_date('12/01/2015', 'dd/mm/yyyy'), to_date('20/01/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 344, to_date('27/01/2015', 'dd/mm/yyyy'), to_date('03/02/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 455, to_date('07/02/2015', 'dd/mm/yyyy'), to_date('10/02/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 431, to_date('17/02/2015', 'dd/mm/yyyy'), to_date('23/02/2015', 'dd/mm/yyyy') from dual;
commit;
insert into xxa_xxb_tmp_res (item, price, start_date, end_date)
with date_range as (select least(xa.min_start_date, xb.min_start_date) range_start,
greatest(xa.max_end_date, xb.max_end_date) range_end
from (select min(start_date) min_start_date,
max(end_date) max_end_date
from xxa) xa
cross join
(select min(start_date) min_start_date,
max(end_date) max_end_date
from xxb) xb),
dates as (select range_start + level -1 dt
from date_range
connect by range_start + level -1 <= range_end),
pivot_xxa as (select xxa.item,
xxa.price,
dts.dt
from xxa
inner join dates dts on (dts.dt between xxa.start_date and xxa.end_date)),
pivot_xxb as (select xxb.item,
xxb.price,
dts.dt
from xxb
inner join dates dts on (dts.dt between xxb.start_date and xxb.end_date)),
res as (select coalesce(pxb.item, pxa.item) item,
coalesce(pxb.price, pxa.price) price,
coalesce(pxa.dt, pxb.dt) dt,
row_number() over (partition by coalesce(pxb.item, pxa.item) order by coalesce(pxa.dt, pxb.dt))
- row_number() over (partition by coalesce(pxb.item, pxa.item), coalesce(pxb.price, pxa.price) order by coalesce(pxa.dt, pxb.dt)) grp
from pivot_xxa pxa
full outer join pivot_xxb pxb on (pxa.item = pxb.item
and pxa.dt = pxb.dt))
select item,
price,
min(dt) start_date,
max(dt) end_date
from res
group by item,
price,
grp;
delete from xxa where item in (select item from xxa_xxb_tmp_res);
insert into xxa (item, price, start_date, end_date)
select item, price, start_date, end_date
from xxa_xxb_tmp_res;
commit;
select * from xxa
order by item, start_date;
ITEM PRICE START_DATE END_DATE
----- ---------- ---------- ----------
plug 345 01/01/2015 10/01/2015
plug 12 11/01/2015 11/01/2015
plug 133 12/01/2015 20/01/2015
plug 1 21/01/2015 25/01/2015
plug 344 27/01/2015 03/02/2015
plug 3 04/02/2015 04/02/2015
plug 4 05/02/2015 06/02/2015
plug 455 07/02/2015 10/02/2015
plug 431 17/02/2015 23/02/2015
plug 43 24/02/2015 25/02/2015
drop table xxa;
drop table xxb;
drop table xxa_xxb_tmp_res;
大部分工作都是在第一个插入语句中完成的 - 基本上,我在做的是将每个表中的范围扩展为单独的行,然后将全部外部连接起来,然后再使用xxb表&#39 ; s列优先于xxa&#39; s。获得该信息后,我使用tabibitosan方法将结果重新分组回范围。
好的,这是使用合并的方法,但它确实意味着xxa表需要有一个主键(或一些其他列来标识每个项目的行)。注:如果xxa表中的行数多于组合的xxa / xxb结果,则&#34; extra&#34;行将在price,start_date和end_date列中具有空值。 (我仍然认为应删除这些行!):
create table xxa (pk_col number,
item varchar2(5),
price number,
start_date date,
end_date date,
constraint xxa_pk primary key (pk_col));
create table xxb (item varchar2(5),
price number,
start_date date,
end_date date);
create sequence xxa_seq
start with 1
maxvalue 999999999999999999999999999
minvalue 1
nocycle
cache 20
noorder;
insert into xxa
select xxa_seq.nextval,
item,
price,
start_date,
end_date
from (select 'plug' item, 12 price, to_date('10/01/2015', 'dd/mm/yyyy') start_date, to_date('15/01/2015', 'dd/mm/yyyy') end_date from dual union all
select 'plug', 1, to_date('20/01/2015', 'dd/mm/yyyy'), to_date('25/01/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 3, to_date('30/01/2015', 'dd/mm/yyyy'), to_date('04/02/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 4, to_date('05/02/2015', 'dd/mm/yyyy'), to_date('10/02/2015', 'dd/mm/yyyy') from dual union all
select 'fork', 10, to_date('02/01/2015', 'dd/mm/yyyy'), to_date('20/01/2015', 'dd/mm/yyyy') from dual union all
select 'fork', 20, to_date('22/01/2015', 'dd/mm/yyyy'), to_date('28/01/2015', 'dd/mm/yyyy') from dual union all
select 'fork', 30, to_date('01/02/2015', 'dd/mm/yyyy'), to_date('10/02/2015', 'dd/mm/yyyy') from dual union all
select 'club', 10, to_date('02/01/2015', 'dd/mm/yyyy'), to_date('20/01/2015', 'dd/mm/yyyy') from dual union all
select 'club', 20, to_date('22/01/2015', 'dd/mm/yyyy'), to_date('28/01/2015', 'dd/mm/yyyy') from dual union all
select 'club', 30, to_date('01/02/2015', 'dd/mm/yyyy'), to_date('10/02/2015', 'dd/mm/yyyy') from dual);
insert into xxb
select 'plug', 345, to_date('01/01/2015', 'dd/mm/yyyy'), to_date('10/01/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 133, to_date('12/01/2015', 'dd/mm/yyyy'), to_date('20/01/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 344, to_date('27/01/2015', 'dd/mm/yyyy'), to_date('03/02/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 455, to_date('07/02/2015', 'dd/mm/yyyy'), to_date('10/02/2015', 'dd/mm/yyyy') from dual union all
select 'plug', 431, to_date('17/02/2015', 'dd/mm/yyyy'), to_date('23/02/2015', 'dd/mm/yyyy') from dual union all
select 'fork', 15, to_date('15/01/2015', 'dd/mm/yyyy'), to_date('18/01/2015', 'dd/mm/yyyy') from dual union all
select 'fork', 25, to_date('24/01/2015', 'dd/mm/yyyy'), to_date('08/02/2015', 'dd/mm/yyyy') from dual union all
select 'club', 100, to_date('03/01/2015', 'dd/mm/yyyy'), to_date('20/02/2015', 'dd/mm/yyyy') from dual;
commit;
merge into xxa tgt
using (with date_range as (select least(xa.min_start_date, xb.min_start_date) range_start,
greatest(xa.max_end_date, xb.max_end_date) range_end
from (select min(start_date) min_start_date,
max(end_date) max_end_date
from xxa) xa
cross join
(select min(start_date) min_start_date,
max(end_date) max_end_date
from xxb) xb),
dates as (select range_start + level -1 dt
from date_range
connect by range_start + level -1 <= range_end),
pivot_xxa as (select xxa.item,
xxa.price,
dts.dt
from xxa
inner join dates dts on (dts.dt between xxa.start_date and xxa.end_date)),
pivot_xxb as (select xxb.item,
xxb.price,
dts.dt
from xxb
inner join dates dts on (dts.dt between xxb.start_date and xxb.end_date)),
res as (select coalesce(pxb.item, pxa.item) item,
coalesce(pxb.price, pxa.price) price,
coalesce(pxa.dt, pxb.dt) dt,
row_number() over (partition by coalesce(pxb.item, pxa.item) order by coalesce(pxa.dt, pxb.dt))
- row_number() over (partition by coalesce(pxb.item, pxa.item), coalesce(pxb.price, pxa.price) order by coalesce(pxa.dt, pxb.dt)) grp
from pivot_xxa pxa
full outer join pivot_xxb pxb on (pxa.item = pxb.item
and pxa.dt = pxb.dt)),
final_res as (select item,
price,
min(dt) start_date,
max(dt) end_date,
row_number() over (partition by item order by min(dt)) rn
from res
group by item,
price,
grp),
xxa_rn as (select pk_col,
item,
price,
start_date,
end_date,
row_number() over (partition by item order by start_date) rn
from xxa)
select coalesce(fr.item, xa.item) item,
fr.price,
fr.start_date,
fr.end_date,
xa.pk_col
from final_res fr
full outer join xxa_rn xa on (fr.item = xa.item and fr.rn = xa.rn)) src
on (tgt.item = src.item and tgt.pk_col = src.pk_col)
when matched then
update set tgt.price = src.price,
tgt.start_date = src.start_date,
tgt.end_date = src.end_date
when not matched then
insert (pk_col, tgt.item, tgt.price, tgt.start_date, tgt.end_date)
values (xxa_seq.nextval, src.item, src.price, src.start_date, src.end_date);
commit;
select * from xxa
order by item, start_date;
PK_COL ITEM PRICE START_DATE END_DATE
---------- ----- ---------- ---------- ----------
8 club 10 02/01/2015 02/01/2015
9 club 100 03/01/2015 20/02/2015
10 club
5 fork 10 02/01/2015 14/01/2015
6 fork 15 15/01/2015 18/01/2015
7 fork 10 19/01/2015 20/01/2015
27 fork 20 22/01/2015 23/01/2015
26 fork 25 24/01/2015 08/02/2015
22 fork 30 09/02/2015 10/02/2015
1 plug 345 01/01/2015 10/01/2015
2 plug 12 11/01/2015 11/01/2015
3 plug 133 12/01/2015 20/01/2015
4 plug 1 21/01/2015 25/01/2015
25 plug 344 27/01/2015 03/02/2015
23 plug 3 04/02/2015 04/02/2015
28 plug 4 05/02/2015 06/02/2015
21 plug 455 07/02/2015 10/02/2015
24 plug 431 17/02/2015 23/02/2015
drop table xxa;
drop table xxb;
drop sequence xxa_seq;