update using for loop in plsql

前端 未结 2 2039
猫巷女王i
猫巷女王i 2021-01-18 11:10

i\'m having problem updating and insert into below column. Please advise on this.

This is the input

depnto   extra    comm
--------------------------         


        
2条回答
  •  执念已碎
    2021-01-18 11:25

    You do not need FOR LOOP, just a single UPDATE does the work:

    UPDATE emp
      SET comm = extra
    WHERE comm IS NULL AND extra IS NOT NULL;
    

    Here is a demo: http://www.sqlfiddle.com/#!4/aacc3/1

    --- EDIT ----

    I didn't notice, that in the expected output deptno 10 was updated to 20,
    to update deptno an another query is needed:

    UPDATE emp
       SET deptno = 20
    WHERE deptno = 10;
    



    ---- EDIT -----

    If you want to insert changed values to the other table, try a procedure with RETURNING..BULK COLLECT and FORALL:

    CREATE OR REPLACE PROCEDURE pro_cedure( p_dept_id number  ) 
    IS
          TYPE changed_table_type IS TABLE OF changed%ROWTYPE;
          changed_buff changed_table_type;
    BEGIN
          SELECT deptno, comm, extra BULK COLLECT INTO changed_buff
          FROM emp
          WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id
          FOR UPDATE;
          UPDATE emp
          SET comm = extra
          WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id;
          FORALL i IN 1 .. changed_buff.count
            INSERT INTO changed VALUES changed_buff( i );
    END;
    /
    

    The procedure should work if you are not going to process huge number of records in a one call (more than 1000 ... or maximum a few thousands). If one dept_id can contain ten thousands and more rows, then this procedure might be slow, becasue it will consume a huge amount of PGA memory. In such a case, an another approach with bulk collectiong in chunks is required.

    -- EDIT --- how to store sequence values -------

    I assume that the table changed has 4 columns, like this:

      CREATE TABLE "TEST"."CHANGED" 
       (    "DEPTNO" NUMBER, 
            "OLDVAL" NUMBER, 
            "NEWVAL" NUMBER, 
            "SEQ_NEXTVAL" NUMBER 
       ) ;
    

    and we will store sequence values in the seq_nextval column.

    In such a case the procedure might look like this:

    create or replace 
    PROCEDURE pro_cedure( p_dept_id number  ) 
    IS
          TYPE changed_table_type IS TABLE OF changed%ROWTYPE;
          changed_buff changed_table_type;
    BEGIN
          SELECT deptno, comm, extra, sequence_name.nextval 
            BULK COLLECT INTO changed_buff
            FROM emp
            WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id
            FOR UPDATE;
          UPDATE emp
            SET comm = extra
            WHERE comm IS NULL AND extra IS NOT NULL AND deptno = p_dept_id;
          FORALL i IN 1 .. changed_buff.count
            INSERT INTO changed VALUES changed_buff( i );
    END;
    



    --- EDIT --- version with cursor for small sets of data -----

    Yes, for small sets of data bulk collecting doesn't give significant increase of the speed, and plain cursor with for..loop is sufficient in such a case.
    Below is an example how tu use the cursor together with update, notice the FOR UPDATE clause, it is required when we plan to update a record fetched from the cursor using WHERE CURRENT OF clause.
    This time a sequence value is evaluated within the INSERT statement.

    create or replace 
    PROCEDURE pro_cedure( p_dept_id number  ) 
    IS
          CURSOR mycursor IS 
             SELECT deptno, comm, extra
             FROM emp
             WHERE comm IS NULL AND extra IS NOT NULL 
                   AND deptno = p_dept_id
             FOR UPDATE;    
    BEGIN
          FOR emp_rec IN  mycursor
          LOOP
             UPDATE emp 
                SET comm = extra
                WHERE CURRENT OF mycursor;
             INSERT INTO changed( deptno, oldval, newval, seq_nextval)
                    VALUES( emp_rec.deptno, emp_rec.comm, 
                            emp_rec.extra, sequence_name.nextval );
          END LOOP;
    END;
    

提交回复
热议问题