我编写了这个程序,旨在根据订单详细信息中的pno和ono单独删除项目。删除的项目将相应地放入表RECORDS和REMOVED_ODETAILS中。订单不止一次购买的一些商品,以及每件商品的购买数量,即数量。我的问题是如何减少订购多次的商品的数量-1,并增加数量EVTY REMOVED_ODETAILS +1?
create or replace PROCEDURE ONE_BY_ONE( ORD_NUM IN NUMBER(5), PRO_NUM IN NUMBER(5), QUANTITY NUMBER(5))
AS
CURSOR CUR1
IS
SELECT * FROM ORDERS
WHERE ONO = ORD_NUM;
CURSOR CUR2
IS
SELECT * FROM ODETAILS
WHERE PNO = PRO_NUM
AND ONO = P_ONO;
VAL1 CUR1%ROWTYPE;
VAL2 CUR2%ROWTYPE;
BEGIN
OPEN CUR1;
OPEN CUR2;
LOOP
FETCH CUR1 INTO VAL1;
FETCH CUR2 INTO VAL2;
EXIT WHEN CUR1%NOTFOUND;
EXIT WHEN CUR1%NOTFOUND;
IF VAL1.SHIPPED IS NOT NULL THEN
IF PRO_NUM = VAL2.PNO AND ORD_NUM = VAL2.ONO THEN
IF ( VAL2.QTY > QUANTITY) THEN
FOR R IN (SELECT ONO, PNO FROM REMOVED_ODETAILS) LOOP
--CODE NOT CHECK TO INSERT OR UPDATE ON REMOVED_ODETAILS
IF (R.ONO != ORD_NUM AND R.PNO != PRO_NUM) THEN
INSERT
INTO REMOVED_ODETAILS
(
ONO,
PNO,
QTY
)
VALUES
(
VAR_CUR2.ONO,
VAR_CUR2.PNO,
VAR_CUR2.QTY
);
ELSE
UPDATE REMOVED_ODETAILS SET QTY = QTY - QUANTITY WHERE ONO = ORD_NUM AND
PNO =PRO_NUM;
END IF;
END LOOP;
INSERT INTO RECORDS(ID_NUMBER, ONO,CNO,DATE_SEND,CONDITION)
VALUES(Seq.NEXTVAL, VAL1.ONO,VAL1.CNO,SYSDATE,'SEND BACK');
ELSIF (VAL2.QTY = QUANTITY ) THEN
INSERT INTO RECORDS(ID_NUMBER, ONO,CNO,DATE_SEND,CONDITION)
VALUES(Seq.NEXTVAL, VAL1.ONO,VAL1.CNO,SYSDATE,'SEND BACK');
INSERT INTO REMOVED_ODETAILS( ONO, PNO, QTY)
VALUES(VAR_CUR2.ONO,VAR_CUR2.PNO, VAR_CUR2.QTY);
DELETE FROM ODETAILS WHERE ONO = ORD_NUM AND `enter code here`PNO = PRO_NUM;
END IF;
DBMS_OUTPUT.PUT_LINE('Item will be send back ');
DELETE FROM ORDERS
WHERE ONO = ORD_NUM and
NOT EXISTS (select 1 from ODETAILS where ONO = ORD_NUM );
ELSIF VAL1.SHIPPED IS NULL THEN
DBMS_OUTPUT.PUT_LINE('DO NOTHING ');
END IF;
END LOOP;
CLOSE CUR1;
CLOSE CUR2;
END ONE_BY_ONE;
客户
create table customers (
cno number(5) not null primary key,
cname varchar2(30),
street varchar2(30),
zip number(5) references zipcodes,
phone char(12));
EMPLOYEES
create table employees (
eno number(4) not null primary key,
ename varchar2(30),
zip number(5) references zipcodes,
hdate date);
订单
create table orders (
ono number(5) not null primary key,
cno number(5) references customers,
eno number(4) references employees,
received date,
shipped date);
ODETAILS
create table odetails (
ono number(5) not null references orders,
pno number(5) not null references parts,
qty integer check(qty > 0),
primary key (ono,pno));
记录
create table RECORDS
id_number number(5) not null primary key,
ono number(5) not null,
cno number(5) not null,
date_send date,
condition varchar22(30));
REMOVED_ODETAILS
create table REMOVED_ODETAILS (
ono number(5) not null,
pno number(5) not null,
qty integer check(qty > 0),
primary key (ono,pno));
订单
ONO CNO ENO RECEIVED DATE SHIPPED DATE
---------- ---------- ---------- ----------- ----------
1112 7000 1004 02-JAN-16 20-DEC-15
1113 12345 2002 10-JAN-16 15-DEC-15
1114 12345 2002 09-JAN-16 14-DEC-15
ODETAILS
ONO PNO QTY
---------- ---------- ----------
1112 12345 3
1112 98766 3
1113 12345 2
1114 12345 1
记录
ID_NUMBER ONO CNO DATE_SEND CONDITION
------------ ------- -------- ---------- --------
10001 1112 7000 13-JAN-16 SEND BACK
10002 1112 7000 13-JAN-16 SEND BACK
10003 1112 7000 13-JAN-16 SEND BACK
10005 1113 12345 14-JAN-16 SEND BACK
10006 1114 12345 14-JAN-16 SEND BACK
REMOVED_ODETAILS
ONO PNO QTY
------- ------ ------
1112 12345 2
1112 98766 1
1113 12345 1
1114 12345 1
ODETAILS
ONO PNO QTY
---------- ---------- ----------
1112 12345 1
1112 98766 2
1113 12345 1
订单
ONO CNO ENO RECEIVED DATE SHIPPED DATE
---------- ---------- ---------- ----------- ----------
1112 7000 1004 02-JAN-16 20-DEC-15
1113 12345 2002 10-JAN-16 15-DEC-15
答案 0 :(得分:0)
以下是我编写程序的方法:
create or replace procedure one_by_one (p_ord_num in number,
p_pro_num in number,
p_qty in number)
is
begin
insert into records (id_number, ono, cno, date_send, condition)
select records_seq.nextval,
o.ono,
o.cno,
trunc(sysdate) date_send, -- should include the time? if so, remove the trunc()
'SEND BACK' condition
from orders o
cross join (select level lvl
from dual
connect by level <= p_qty) d
where o.ono = p_ord_num
and shipped is not null;
merge into removed_odetails tgt
using (select p_ord_num ono,
p_pro_num pno,
p_qty qty
from dual) src
on (tgt.ono = src.ono and tgt.pno = src.pno)
when not matched then
insert (tgt.ono, tgt.pno, tgt.qty)
values (src.ono, src.pno, src.qty)
when matched then
update
set tgt.qty = tgt.qty + src.qty;
merge into odetails tgt
using (select p_ord_num ono,
p_pro_num pno,
p_qty qty
from dual) src
on (tgt.ono = src.ono and tgt.pno = src.pno)
when matched then
update set tgt.qty = tgt.qty - case when tgt.qty > src.qty then src.qty end
delete
where tgt.qty is null;
delete from orders
where ono = p_ord_num
and ono not in (select ono
from odetails
where ono = p_ord_num);
end;
/
这是一个测试案例,证明它有效:
drop procedure one_by_one;
drop table removed_odetails;
drop table records;
drop table odetails;
drop table orders;
drop sequence records_seq;
create table orders (
ono number(5) not null primary key,
cno number(5), --references customers,
eno number(4), --references employees,
received date,
shipped date);
create table odetails (
ono number(5) not null references orders,
pno number(5) not null, --references parts,
qty integer check(qty > 0),
primary key (ono,pno));
create table records (
id_number number(5) not null primary key,
ono number(5) not null,
cno number(5) not null,
date_send date,
condition varchar2(30));
create sequence records_seq
start with 10001
maxvalue 999999999999999999999999999
minvalue 1
nocycle
cache 20
noorder;
create table removed_odetails (
ono number(5) not null,
pno number(5) not null,
qty integer check(qty > 0),
primary key (ono,pno));
insert into orders (ono, cno, eno, received, shipped)
select 1112 ono, 7000 cno, 1004 eno, to_date('02/01/2016', 'dd/mm/yyyy') received, to_date('20/12/2015', 'dd/mm/yyyy') shipped from dual union all
select 1113 ono, 12345 cno, 2002 eno, to_date('10/01/2016', 'dd/mm/yyyy') received, to_date('15/12/2015', 'dd/mm/yyyy') shipped from dual union all
select 1114 ono, 12345 cno, 2002 eno, to_date('09/01/2016', 'dd/mm/yyyy') received, to_date('14/12/2015', 'dd/mm/yyyy') shipped from dual;
insert into odetails (ono, pno, qty)
select 1112 ono, 12345 pno, 3 qty from dual union all
select 1112 ono, 98766 pno, 3 qty from dual union all
select 1113 ono, 12345 pno, 2 qty from dual union all
select 1114 ono, 12345 pno, 1 qty from dual;
commit;
-- now run the procedure for all rows in removed_odetails:
begin
for rec in (select 1112 ono, 12345 pno, 2 qty from dual union all
select 1112 ono, 98766 pno, 1 qty from dual union all
select 1113 ono, 12345 pno, 1 qty from dual union all
select 1114 ono, 12345 pno, 1 qty from dual)
loop
one_by_one(p_ord_num => rec.ono,
p_pro_num => rec.pno,
p_qty => rec.qty);
end loop;
commit;
end;
/
select * from orders;
ONO CNO ENO RECEIVED SHIPPED
---------- ---------- ---------- ---------- ----------
1112 7000 1004 02/01/2016 20/12/2015
1113 12345 2002 10/01/2016 15/12/2015
select * from odetails;
ONO PNO QTY
---------- ---------- ----------
1112 12345 1
1112 98766 2
1113 12345 1
select * from removed_odetails;
ONO PNO QTY
---------- ---------- ----------
1112 98766 1
1112 12345 2
1114 12345 1
1113 12345 1
select * from records;
ID_NUMBER ONO CNO DATE_SEND CONDITION
---------- ---------- ---------- ---------- ------------------------------
10001 1112 7000 14/01/2016 SEND BACK
10002 1112 7000 14/01/2016 SEND BACK
10003 1112 7000 14/01/2016 SEND BACK
10004 1113 12345 14/01/2016 SEND BACK
10005 1114 12345 14/01/2016 SEND BACK
begin
for rec in (select 1112 ono, 98766 pno, 1 qty from dual)
loop
one_by_one(p_ord_num => rec.ono,
p_pro_num => rec.pno,
p_qty => rec.qty);
end loop;
commit;
end;
/
select * from orders;
ONO CNO ENO RECEIVED SHIPPED
---------- ---------- ---------- ---------- ----------
1112 7000 1004 02/01/2016 20/12/2015
1113 12345 2002 10/01/2016 15/12/2015
select * from odetails;
ONO PNO QTY
---------- ---------- ----------
1112 12345 1
1112 98766 1
1113 12345 1
select * from removed_odetails;
ONO PNO QTY
---------- ---------- ----------
1112 98766 2
1112 12345 2
1114 12345 1
1113 12345 1
select * from records;
ID_NUMBER ONO CNO DATE_SEND CONDITION
---------- ---------- ---------- ---------- ------------------------------
10001 1112 7000 14/01/2016 SEND BACK
10002 1112 7000 14/01/2016 SEND BACK
10003 1112 7000 14/01/2016 SEND BACK
10004 1113 12345 14/01/2016 SEND BACK
10005 1114 12345 14/01/2016 SEND BACK
10006 1112 7000 14/01/2016 SEND BACK
是的,你看到上面的测试用例?这是您应该提前提供的信息类型,以避免浪费时间让志愿者帮助您......免费。当你发布未来的问题时,请把它带到船上!
答案 1 :(得分:0)
这是一个工作(好吧,似乎每个调用只添加一行ono / pno组合到记录表中,而不是对应于被删除数量的行数)代码版本:
create or replace procedure one_by_one( ord_num in number, pro_num in number, quantity number)
as
cursor cur1
is
select * from orders
where ono = ord_num;
cursor cur2
is
select * from odetails
where pno = pro_num
and ono = ord_num;
val1 cur1%rowtype;
val2 cur2%rowtype;
begin
open cur1;
open cur2;
loop
fetch cur1 into val1;
fetch cur2 into val2;
exit when cur1%notfound;
exit when cur1%notfound;
if val1.shipped is not null then
-- if pro_num = val2.pno and ord_num = val2.ono then -- totally unnecessary, since you already did that check as part of the cursor!
if (val2.qty > quantity) then
merge into removed_odetails tgt
using (select ord_num ono,
pro_num pno,
quantity qty
from dual) src
on (tgt.ono = src.ono and tgt.pno = src.pno)
when not matched then
insert (tgt.ono, tgt.pno, tgt.qty)
values (src.ono, src.pno, src.qty)
when matched then
update
set tgt.qty = tgt.qty + src.qty;
update odetails
set qty = qty - quantity
where ono = ord_num
and pno = pro_num;
insert into records(id_number, ono,cno,date_send,condition)
values(records_seq.nextval, val1.ono,val1.cno,sysdate,'SEND BACK');
elsif (val2.qty = quantity ) then
insert into records(id_number, ono,cno,date_send,condition)
values (records_seq.nextval, val1.ono,val1.cno,sysdate,'SEND BACK');
insert into removed_odetails( ono, pno, qty)
values(val2.ono,val2.pno, val2.qty);
delete from odetails where ono = ord_num and pno = pro_num;
end if;
dbms_output.put_line('Item will be send back ');
delete from orders
where ono = ord_num
and not exists (select null from odetails where ono = ord_num);
elsif val1.shipped is null then
dbms_output.put_line('DO NOTHING ');
end if;
end loop;
close cur1;
close cur2;
end one_by_one;
/
当你试图检查remove_odetails表中是否已存在某行时,你试图重新发明MERGE
语句,所以我所做的就是删除游标for循环并拥有而是改为使用merge语句(并将removed_odetails表的更新更改为更新odetails表)。
我不建议这个特定的解决方案;它比我提供的其他解决方案简单得多。如果您需要在将来的任何时候维护此代码,您将诅咒自己! (我们都去过那里......)