【问题标题】:Execute delete and update the respective rows in other table执行删除和更新其他表中的相应行
【发布时间】:2012-09-30 12:48:49
【问题描述】:

我有以下表格

CREATE TABLE A2SKU 
(
  SKUID NUMBER NOT NULL,
  SKUNAME VARCHAR2(20),
  SKUQTY NUMBER, 
  CONSTRAINT A2SKU_PK PRIMARY KEY (SKUID)
);


CREATE TABLE A2LOC 
(
  LOCID NUMBER NOT NULL, 
  LOCNAME VARCHAR2(20), 
  LOCQTY NUMBER, 
  MAXQTY NUMBER, 
  CONSTRAINT A2LOC_PK PRIMARY KEY (LOCID)
);



Create Table A2BOX ( 
boxId NUMBER Primary Key, 
skuId NUMBER, 
locId NUMBER, 
constraint FK_A2BOX_SKUID foreign key (skuid) references A2SKU, 
constraint FK_A2BOX_LOCID foreign key (locid) references A2LOC
);


CREATE SEQUENCE A2BOXSEQ;

我想从 A2Box 表中删除所有具有匹配 SKU 的框,并将每个框的 A2Loc 表中匹配位置的 LocQty 调整 1

我如何使用存储过程来做到这一点。

我自己试了一下,想出了这个

create or replace procedure A2DeleteSKU
(
pskuid IN number
)
AS
CURSOR row_cursor IS
      SELECT boxid,locid from A2BOX where skuid =  pskuid;
skuid_count Number;
skuid_check exception;

sku_rec row_cursor%rowtype;

Begin
select count(*) into skuid_count from A2SKU where skuid = pskuid;
if skuid_count <1 then
raise skuid_check;
End If;

 FOR sku_rec in row_cursor 

LOOP 
    delete from a2box where boxid = sku_rec.boxid;
    update A2LOC set locqty = locqty -1 where locid = sku_rec.locid;
 END LOOP;

   delete from A2SKU where skuid =pskuid;
   commit;
Exception
When skuid_check then
  RAISE_APPLICATION_ERROR(-20014, 'Delete Box failed. Boxid does not exist: '||TO_CHAR(pskuid));
When others then
raise;
End A2DeleteSku;

【问题讨论】:

    标签: sql oracle plsql cursor oracle11g


    【解决方案1】:

    这是使用RETURNING INTO 子句的绝佳机会,当与BULK COLLECT 结合使用时会非常有用。

    为了使用它,您必须设置一个数组来保存您要删除的locid。由于每个 SKUID 可能有多个 locids,因此您可能必须将每个 locid 的数量减少一个以上。

    create or replace procedure remove_boxes ( PSKUID number ) is
    
       -- Set up an array to hold the deletes
       type t__locid is table of a2loc.locid%type index by binary_integer;
       t_locid t__locid;
    
    begin
    
       -- Delete the rows and return the deleted locids
          delete from a2box
           where skuid = PSKUID
       returning locid
            bulk collect into t_locid
                 ;
    
       for i in t_locid.first .. t_locid.last loop
          update a2loc
             set locqty = locqty - 1
           where locid = t_locid(i)
                 ;
       end loop;
    
    end remove_boxes;
    /
    

    您可以将for .. loop 更改为forall,但我以前从未这样做过,也找不到您可以这样做的确认。如果可能的话,它看起来像这样:

    forall i in t_locid.first .. t_locid.last
       update a2loc
          set locqty = locqty - 1
        where locid = t_locid(i)
              ;
    

    作为Tom Kyte suggests,我强烈建议索引外键;在这种情况下肯定会更好。

    【讨论】:

    • 不需要使用行处理,两条语句——一个更新,一个删除——就像下面的其他答案一样,也可以提高性能。
    • 当然@colin,我提供了一个替代方案......(当前)赞成的答案确实做了不必要的索引范围扫描......(假设列被索引)。
    • 感谢您的支持。我已经用我的解决方案进行了编辑。请检查可以吗?谢谢
    • 另外,@Colin'tHart 现在我想你必须进行行级处理,因为你可以删除同一个 skuid 的多个 locid,所以其他答案不正确。
    【解决方案2】:
    CREATE PROCEDURE remove_boxes(pp_skuId NUMBER) IS
    BEGIN
        UDPATE a2loc SET locqty = locqty - 1
          WHERE locid IN (SELECT locid FROM a2box
                            WHERE skuId = pp_skuId);
        DELETE FROM a2box
          WHERE skuId = pp_skuId;
    END;
    

    我不确定您将 locqty 调整为 1 是什么意思。您必须以正确的方式修改更新命令

    【讨论】:

      【解决方案3】:

      据我了解,A2LOC 上的 LOCQTY 列表示具有相应 locid 的框的摘要,您希望在移除框时对其进行调整。所以,检查以下代码:

      create or replace procedure adjustLoc(p_skuid number) is
      begin
      
      -- Adjusts the locqty value
      update A2LOC loc
        set LOCQTY = LOCQTY  -1
       where exists(select 1 
                      from A2BOX box
                     where box.locid = loc.locid
                       and box.skuid = p_skuid);
      
      -- Removes all sku matching boxes
      Delete A2BOX 
      where skuid = p_skuid;
      
      end;
      

      【讨论】:

        【解决方案4】:
        create or replace procedure A2DeleteSKU
        (
        pskuid IN number
        )
        AS
        CURSOR row_cursor IS
              SELECT boxid,locid from A2BOX where skuid =  pskuid;
        skuid_count Number;
        skuid_check exception;
        
        sku_rec row_cursor%rowtype;
        
        Begin
        select count(*) into skuid_count from A2SKU where skuid = pskuid;
        if skuid_count <1 then
        raise skuid_check;
        End If;
        
         FOR sku_rec in row_cursor 
        
        LOOP 
            delete from a2box where boxid = sku_rec.boxid;
            update A2LOC set locqty = locqty -1 where locid = sku_rec.locid;
         END LOOP;
        
           delete from A2SKU where skuid =pskuid;
           commit;
        Exception
        When skuid_check then
          RAISE_APPLICATION_ERROR(-20014, 'Delete Box failed. Boxid does not exist: '||TO_CHAR(pskuid));
        When others then
        raise;
        End A2DeleteSku;
        

        【讨论】:

        • 呃,一个过程中的commit。如果你把它称为更大的交易呢?
        • @DReispt,在过程中提交本质上没有任何问题。问题是,正如你所说,你必须知道你从哪里调用它......
        猜你喜欢
        • 2021-02-17
        • 2012-09-02
        • 2020-05-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-13
        • 2013-10-03
        相关资源
        最近更新 更多