sql >> Databasteknik >  >> RDS >> Oracle

uppdatera med for loop i plsql

Du behöver inte FOR LOOP , bara en enda UPPDATERING fungerar:

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

Här är en demo:http://www.sqlfiddle.com/#!4/ aacc3/1

--- REDIGERA ----

Jag märkte inte att i den förväntade utgången uppdaterades avd 10 till 20,
för att uppdatera avdnr en annan fråga behövs:

UPDATE emp
   SET deptno = 20
WHERE deptno = 10;



---- REDIGERA -----

Om du vill infoga ändrade värden i den andra tabellen, prova en procedur med RETURNING..BULK COLLECT och 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;
/

Proceduren bör fungera om du inte ska behandla ett stort antal poster i ett samtal (mer än 1000 ... eller högst några tusentals). Om en dept_id kan innehålla tiotusentals och fler rader, då kan denna procedur vara långsam, eftersom den kommer att förbruka en enorm mängd PGA-minne. I ett sådant fall krävs ett annat tillvägagångssätt med bulksamling i bitar.

-- REDIGERA --- hur man lagrar sekvensvärden -------

Jag antar att tabellen ändrades har 4 kolumner, så här:

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

och vi kommer att lagra sekvensvärden i seq_nextval kolumn.

I ett sådant fall kan proceduren se ut så här:

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 med markör för små uppsättningar data -----

Ja, för små uppsättningar av data ger inte bulk insamling någon signifikant ökning av hastigheten, och vanlig markör med for..loop räcker i ett sådant fall.
Nedan är ett exempel hur du använder markören tillsammans med uppdatering, lägg märke till FÖR UPPDATERING klausul, krävs det när vi planerar att uppdatera en post som hämtas från markören med WHERE CURRENT OF sats.
Den här gången utvärderas ett sekvensvärde i INSERT-satsen.

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;


  1. Kan inte skapa PoolableConnectionFactory

  2. Hur man ringer Oracles lagrade procedur från azure data factory v2

  3. Escape SQL LIKE-värde för Postgres med psycopg2

  4. Kan jag sätta ignore_dup_key på för en primärnyckel?