Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

update using for loop in plsql

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

This is the input

depnto   extra    comm
----------------------------
20       300      NULL
20       300      400
20       NULL     NULL
20       500      NULL

This is the expected output

depnto  Extra    comm
---------------------
20      300      300
20      300      400
20      NULL     NULL           
20      500      500

I need to update comm column with extra column on below conditions.

  • If comm Is null then extra value is updated to comm.
  • If comm Is not null, no need to update,
  • If both are null, leave as null,
  • if comm column has a value no need to overwrite.

My program is below. Even I need to keep track which are rows are updated and to which value in another table.

PROCEDURE (dept_id )
AS
BEGIN
   FOR r IN (SELECT *
               FROM emp
              WHERE comm IS NULL AND extra IS NOT NULL AND deptno = dept_id)
   LOOP
      UPDATE emp
         SET comm = extra
       WHERE comm IS NULL AND extra IS NOT NULL AND deptno = dept_id;



      INSERT INTO changed_comm (deptno, oldval, newval)
           VALUES (dept_id, r.comm, r.extra);
   END LOOP;
EXCEPTION
   WHEN NO_DATA_FOUND
   THEN
      NULL;
END;

please provide some opinion on above. Its not inserting correctly.

like image 601
user2686661 Avatar asked Sep 07 '13 06:09

user2686661


People also ask

What is for update in PL SQL?

The FOR UPDATE clause is an optional part of a SELECT statement. Cursors are read-only by default. The FOR UPDATE clause specifies that the cursor should be updatable, and enforces a check during compilation that the SELECT statement meets the requirements for an updatable cursor.

Can we use for loop in Plsql?

LOOP statements execute a sequence of statements multiple times. The LOOP and END LOOP keywords enclose the statements. PL/SQL provides four kinds of loop statements: basic loop, WHILE loop, FOR loop, and cursor FOR loop.

What is the syntax of for loop in Plsql?

Syntax. LOOP Sequence of statements; END LOOP; Here, the sequence of statement(s) may be a single statement or a block of statements. An EXIT statement or an EXIT WHEN statement is required to break the loop.


2 Answers

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;
like image 115
krokodilko Avatar answered Sep 30 '22 13:09

krokodilko


 BEGIN
      FOR person IN (SELECT A   FROM EMP WHERE B IN (SELECT B FROM ustom.cfd_180518) )
     LOOP
        --dbms_output.put_line(person.A);
        UPDATE custom.cfd_180518 SET c = person.a;
      END LOOP;
 END;  
like image 21
Shashank Shekhar Singh Avatar answered Sep 30 '22 14:09

Shashank Shekhar Singh