Plsql 数量增加/减少pl/sql
我编写了这个过程,旨在从订单详细信息中分别删除基于pno和ono的项目。删除的项目将放入表记录中,并相应地删除详细信息。订单多次采购的某些项目,以及每个项目的采购编号,即数量。我的问题是,对于多次订购的项目,如何从odetails中减少数量-1,并增加删除的数量\u odetails+1Plsql 数量增加/减少pl/sql,plsql,oracle11g,Plsql,Oracle11g,我编写了这个过程,旨在从订单详细信息中分别删除基于pno和ono的项目。删除的项目将放入表记录中,并相应地删除详细信息。订单多次采购的某些项目,以及每个项目的采购编号,即数量。我的问题是,对于多次订购的项目,如何从odetails中减少数量-1,并增加删除的数量\u odetails+1 create or replace PROCEDURE ONE_BY_ONE( ORD_NUM IN NUMBER(5), PRO_NUM IN NUMBER(5), QUANTITY NUMBER(5)) A
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));
雇员
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);
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
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
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));
ONO PNO QTY
---------- ---------- ----------
1112 12345 3
1112 98766 3
1113 12345 2
1114 12345 1
ONO PNO QTY
---------- ---------- ----------
1112 12345 1
1112 98766 2
1113 12345 1
记录
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));
已删除的详细信息
create table REMOVED_ODETAILS (
ono number(5) not null,
pno number(5) not null,
qty integer check(qty > 0),
primary key (ono,pno));
之前
命令
create table orders (
ono number(5) not null primary key,
cno number(5) references customers,
eno number(4) references employees,
received date,
shipped date);
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
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
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));
ONO PNO QTY
---------- ---------- ----------
1112 12345 3
1112 98766 3
1113 12345 2
1114 12345 1
ONO PNO QTY
---------- ---------- ----------
1112 12345 1
1112 98766 2
1113 12345 1
预期答案(当给出特定的ono/pno组合时)
记录
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
已删除的详细信息
ONO PNO QTY
------- ------ ------
1112 12345 2
1112 98766 1
1113 12345 1
1114 12345 1
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));
ONO PNO QTY
---------- ---------- ----------
1112 12345 3
1112 98766 3
1113 12345 2
1114 12345 1
ONO PNO QTY
---------- ---------- ----------
1112 12345 1
1112 98766 2
1113 12345 1
命令
create table orders (
ono number(5) not null primary key,
cno number(5) references customers,
eno number(4) references employees,
received date,
shipped date);
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
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
以下是我将如何编写该过程:
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;
/
顺便说一句,你看到上面的测试用例了吗?这是你应该提前提供的信息类型,以避免浪费那些自愿帮助你的人的时间。。。免费的。当你发布未来的问题时,请记住这一点 下面是您的代码的一个工作版本(好吧,似乎每次调用的ono/pno组合只在records表中添加一行,而不是与被删除的数量对应的行数):
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;
/
您试图重新创建MERGE
语句,当您试图检查删除的\u odetails表中是否已经存在一行时,所以我所做的就是删除循环的游标,改为使用MERGE语句(并将删除的\u odetails表的更新更改为更新odetails表)
但我不推荐这种特殊的解决方案;这比我提供的另一个解决方案要简单得多。如果将来需要维护此代码,您将诅咒自己!(我们都去过那里…如果您能提供CREATETABLE和insert语句,我们就可以复制您的表并自己测试了,这会有所帮助。如果您在程序运行后提供了希望看到的预期输出,这也会有所帮助。我希望我已经对此进行了充分的解释!不幸的是,您提供的额外信息不足以让我们运行您的代码。这就是为什么我要求创建表脚本(包括约束定义,如主键和外键)和insert语句。想象一下,你不是问这个问题的人,而是一个无法访问数据库的人,想要帮助你。你认为你需要什么样的信息才能尝试并提供帮助?最好的问题是有一个完整的测试用例,其他人可以自己使用并运行,这样他们就可以在代码运行之前一直使用代码。我如何将我的表脚本传递给您?如果可以的话,我们可以通过聊天来完成吗?只需编辑您的问题并在其中添加信息。如果您使用精简版的表/数据也可以,只要它们包含足够的信息,我们就可以运行您的代码;希望这次我的手术能达到你的目的!我已经再次更新了我的答案,以确保它在订单/零件发回后再发回的情况下有效。非常感谢您的患者和您的帮助!非常感谢。不过,我希望你能对我再耐心一次。问题,您认为光标可以执行合并语句吗!然后在光标内可以检查删除的\u ODETAILS是否为空,是否插入或更新?只是好奇!可能吧,但是当你在使用代码时,保持简单是值得的。代码越简单,维护、调试和理解就越容易,而且很有可能,它的性能会比更复杂的对应项好得多(尽管显然总是有例外!)。我真的怎么强调都不过分!我理解,我这边可能缺乏经验,因为这是我第一次在PL/SQL{nods}中工作。我认为您的思维非常程序化(也称为逐行)。当涉及到数据库时,它在执行设置操作方面非常强大-例如,不要使用“这里有一个光标,获取一行,插入该行,获取下一行,插入该行,等等…”而只需执行“插入到tablex选择…”即可。更快、更好、更容易阅读、更少的代码等等。如果你习惯于按程序思考,那么很难转变为基于集合的思考!也许会有一些用处?我完全同意你的看法,我喜欢DML,因为它快速、准确、代码高效。然而,我正在尽我最大的努力做到这两个方面,虽然还是新手,但仍在学习:)