【问题标题】:What do I need to use in this? Another cursor, a record or something else?我需要在这个中使用什么?另一个光标,记录还是其他什么?
【发布时间】:2018-02-09 14:50:11
【问题描述】:

下面的代码是我昨天的问题的答案,结果是 ff:

第一次运行

Updated: 0
Inserted: 4

第二次运行

Updated: 4
Inserted: 0

删除 cid '1' 和 '3' 后:

Updated: 2
Inserted: 2
DECLARE
    ins NUMBER := 0;
    upd NUMBER := 0;
    CURSOR c1 IS
        SELECT cid
        FROM tbl_cust
        WHERE cid 
        IN ('1','2','3','4');
BEGIN
    FOR rec IN c1 LOOP
        begin 
           INSERT INTO tbl2 (id_tbl2, name_tbl2)
           VALUES(rec.cid, DECODE(rec.cid, '1', 'A',
                                        '2', 'B',
                                        '3', 'C',
                                        '4', 'D'));
           ins := ins + 1;
        EXCEPTION   WHEN DUP_VAL_ON_INDEX THEN
           UPDATE tbl2 set name_tbl2 = DECODE(rec.cid, '1', 'A',
                                        '2', 'B',
                                        '3', 'C',
                                        '4', 'D'));
           WHERE cust_cust_code = rec.cid;
           upd := upd + 1;
           continue; 
         end;    
    END LOOP;
        dbms_output.put_line('Updated: ' || upd);
        dbms_output.put_line('Inserted: ' || ins);
END;

我现在想要的是在不使用嵌套块的情况下修改这段代码。也许是这样的:

DECLARE
        ins NUMBER := 0;
        upd NUMBER := 0;
        CURSOR c1 IS
            SELECT cid
            FROM tbl_cust
            WHERE cid 
            IN ('1','2','3','4');
        --maybe declare something as 'holder of values' which are ducplicates and cannot be inserted then will be used on a condition or loop to update.    
BEGIN
    FOR rec IN c1 LOOP
       INSERT INTO tbl2 (id_tbl2, name_tbl2)
       VALUES(rec.cid, DECODE(rec.cid, '1', 'A',
                                    '2', 'B',
                                    '3', 'C',
                                    '4', 'D'));
       ins := ins + 1;
       --maybe put some condition here to pass the values that are not insert to the 'holder of values'
   END LOOP;

dbms_output.put_line('Updated: ' || upd);
dbms_output.put_line('Inserted: ' || ins);  

EXCEPTION   
    WHEN DUP_VAL_ON_INDEX THEN
        --maybe put a loop here to update values in the 'holder of values'
        UPDATE tbl2 set name_tbl2 = DECODE('holder of values'.VALUE, '1', 'A',
                                        '2', 'B',
                                        '3', 'C',
                                        '4', 'D')
        WHERE cust_cust_code = 'holder of values'.VALUE;
        upd := upd + 1;
    dbms_output.put_line('Updated: ' || upd);
    dbms_output.put_line('Inserted: ' || ins);
END;

【问题讨论】:

  • 我认为您应该按照@APC 在stackoverflow.com/a/48679336/7998591 中的建议使用MERGE INTO。语法对您来说可能是新的,但值得理解。对于所有循环,我无法弄清楚您在这个问题中的期望。
  • 我已经尝试通过@APC 进行合并,这也是解决此问题的好方法,但我想知道的是一种按照我的想法修改代码的方法。
  • 是的,因为当我们可以花更多时间编写缓慢、难以理解的代码块时,为什么还要以简单、高效的方式编写解决方案?

标签: plsql oracle11g


【解决方案1】:

实际上,最好的方法是merge,正如许多其他人所建议的那样。 (首先要提到的是@APC)

但是,如果您坚持自己的逻辑,那么您应该使用某种集合。 (看看这里Working with Collections)。

尽管如此,你不能将异常处理放在循环之外,它仍然应该在里面。

这可能是这样的:

 DECLARE
        ins NUMBER := 0;
        upd NUMBER := 0;
        CURSOR c1 IS
            SELECT cid
            FROM tbl_cust
            WHERE cid 
            IN ('1','2','3','4');
        --declare something as 'holder of values' 
        TYPE list_of_ids IS TABLE OF number;
        duplicates list_of_ids:= list_of_ids (); 
BEGIN
    FOR rec IN c1 LOOP
       begin  
       INSERT INTO tbl2 (id_tbl2, name_tbl2)
       VALUES(rec.cid, DECODE(rec.cid, '1', 'A',
                                    '2', 'B',
                                    '3', 'C',
                                    '4', 'D'));
        ins := ins + sql%rowcount;
        EXCEPTION   WHEN DUP_VAL_ON_INDEX THEN
        duplicates.EXTEND;
        duplicates(duplicates.LAST):=rec.cid;
        end; 
       --condition here to pass the values that are not insert to the 'holder of values'
   END LOOP;

   dbms_output.put_line('Updated: ' || upd);
   dbms_output.put_line('Inserted: ' || ins);  


      --a loop here to update values in the 'holder of values'
      FOR l_row IN 1 .. duplicates.COUNT
      LOOP
         UPDATE tbl2 set name_tbl2 = DECODE(duplicates (l_row), '1', 'A',
                                        '2', 'B',
                                        '3', 'C',
                                        '4', 'D')
        WHERE cust_cust_code := duplicates (l_row);
        upd := upd + sql%rowcount; 
         DBMS_OUTPUT.put_line (duplicates (l_row));
      END LOOP;

    dbms_output.put_line('Updated: ' || upd);
    dbms_output.put_line('Inserted: ' || ins);
END;

【讨论】:

  • 老兄再次感谢您的回答。使用集合让我知道了如何去做。
  • @SurfaceTension OK 没问题 ;-) 顺便说一句 - 如果答案有任何帮助 - 至少,请投赞成票...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-04
  • 2020-10-11
  • 2011-04-17
  • 2010-09-07
相关资源
最近更新 更多