Oracle-使用CURSOR LOOP进行批量更新

时间:2018-10-05 13:12:55

标签: oracle plsql bulkupdate

我想在像这样的桌子上的一个巨大的桌子上执行更新(我现在不是最好的做法):

TARGET_TABLE (
TICKET_ID number,
product_id number,
NET number(15,2),
VAT number(15,2));

http://sqlfiddle.com/#!4/d39ed/3

目标:UPDATE TARGET_TABLE set NET=VAT, VAT=NET

我想出了一个批量更新,但我在第43行得到了ORA-00913:“ To many values”,我无法解释。另外,我不知道如何在该变体中一次更新两行。 有人可以帮忙吗?

DECLARE

-- new data
    CURSOR new_data_cur IS
      select 
                     a.rowid, 
                     a.TICKET_ID,
                     a.product_id,
                     b.NET,
                     b.VAT
 from TARGET_TABLE a
                     join TARGET_TABLE_COPY b
                     on  ( a.TICKET_ID=b.TICKET_ID AND  a.product_id =b.product_id ) ;

    TYPE new_data_type IS TABLE OF new_data_cur%rowtype INDEX BY PLS_INTEGER;
    new_data_tab       new_data_type;
    TYPE row_id_type IS TABLE OF ROWID INDEX BY PLS_INTEGER;
    row_id_tab         row_id_type;
    TYPE rt_update_cols IS RECORD (
        NET   TARGET_TABLE.NET%TYPE
      --  VAT   TARGET_TABLE.VAT%TYPE
    );
    TYPE update_cols_type IS
        TABLE OF rt_update_cols INDEX BY PLS_INTEGER;
    update_cols_tab1    update_cols_type;
    --update_cols_tab2    update_cols_type;
    dml_errors EXCEPTION;
    PRAGMA exception_init ( dml_errors,-24381 );

BEGIN

    OPEN new_data_cur;
    LOOP
        FETCH new_data_cur BULK COLLECT INTO new_data_tab LIMIT 50000;
        EXIT WHEN new_data_tab.count=0;
        FOR i IN new_data_tab.first..new_data_tab.last LOOP
            row_id_tab(i) := new_data_tab(i).rowid;
            update_cols_tab1(i).NET := new_data_tab(i).VAT;
           -- update_cols_tab2(i).VAT := new_data_tab(i).NET;
        END LOOP;

        FORALL i IN new_data_tab.first..new_data_tab.last SAVE EXCEPTIONS # ORA-00913: To many values
            UPDATE TARGET_TABLE
           -- SET row = update_cols_tab(i)
            SET row = update_cols_tab1(i) 
           --         row = update_cols_tab2(i) 
            WHERE ROWID = row_id_tab(i);

        COMMIT;
        EXIT WHEN new_data_tab.count=0;
    END LOOP;
    COMMIT;
    CLOSE new_data_cur;

    EXCEPTION
    WHEN dml_errors THEN

            FOR i IN 1..SQL%bulk_exceptions.count LOOP
            dbms_output.put_line('Some error occured');
            END LOOP;
    END;

1 个答案:

答案 0 :(得分:0)

我相信您在交换值的地方不需要多余的光标

FOR i IN new_data_tab.first..new_data_tab.last LOOP
        row_id_tab(i) := new_data_tab(i).rowid;
        update_cols_tab1(i).NET := new_data_tab(i).VAT;
       -- update_cols_tab2(i).VAT := new_data_tab(i).NET;
    END LOOP;

因此您的代码将在批量更新中使用这些值

DECLARE

-- new data
CURSOR new_data_cur IS
  select 
                 a.rowid, 
                 a.TICKET_ID,
                 a.product_id,
                 b.NET,
                 b.VAT
   from TARGET_TABLE a
                 join TARGET_TABLE_COPY b
                 on  ( a.TICKET_ID=b.TICKET_ID AND  a.product_id =b.product_id ) ;

TYPE new_data_type IS TABLE OF new_data_cur%rowtype INDEX BY PLS_INTEGER;
new_data_tab       new_data_type;
TYPE row_id_type IS TABLE OF ROWID INDEX BY PLS_INTEGER;
row_id_tab         row_id_type;
TYPE rt_update_cols IS RECORD (
    NET   TARGET_TABLE.NET%TYPE
  --  VAT   TARGET_TABLE.VAT%TYPE
);
TYPE update_cols_type IS
    TABLE OF rt_update_cols INDEX BY PLS_INTEGER;
update_cols_tab1    update_cols_type;
--update_cols_tab2    update_cols_type;
dml_errors EXCEPTION;
PRAGMA exception_init ( dml_errors,-24381 );

BEGIN

OPEN new_data_cur;
LOOP
    FETCH new_data_cur BULK COLLECT INTO new_data_tab LIMIT 50000;
    EXIT WHEN new_data_tab.count=0;


    FORALL i IN new_data_tab.first..new_data_tab.last SAVE EXCEPTIONS # ORA-00913: To many values
        UPDATE TARGET_TABLE
       -- SET row = update_cols_tab(i)
       -- SET row = update_cols_tab1(i) 
       --         row = update_cols_tab2(i) 
        NET =  update_cols_tab1(i).VAT
        VAT = update_cols_tab1(i).NET
        WHERE ROWID = row_id_tab(i);

    COMMIT;
    EXIT WHEN new_data_tab.count=0;
END LOOP;
COMMIT;
CLOSE new_data_cur;

EXCEPTION
WHEN dml_errors THEN

        FOR i IN 1..SQL%bulk_exceptions.count LOOP
        dbms_output.put_line('Some error occured');
        END LOOP;
END;