What do I need to use in this? Another cursor, a record or something else?

时间:2018-02-09 03:56:22

标签: plsql oracle11g

The code below is the answer from my question yesterday that has the ff results:

First run

Updated: 0
Inserted: 4

2nd run

Updated: 4
Inserted: 0

After deleting cid '1' and '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;

What I wanted now is to revise this code without using nested block. Maybe something like this:

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;

1 个答案:

答案 0 :(得分: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;