Plsql 数量增加/减少pl/sql

Plsql 数量增加/减少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

我编写了这个过程,旨在从订单详细信息中分别删除基于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))
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,因为它快速、准确、代码高效。然而,我正在尽我最大的努力做到这两个方面,虽然还是新手,但仍在学习:)