sql >> Database teknologi >  >> RDS >> Oracle

opdatering ved hjælp af for loop i plsql

Du behøver ikke FOR LOOP , kun en enkelt OPDATERING gør arbejdet:

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

Her er en demo:http://www.sqlfiddle.com/#!4/ aacc3/1

--- REDIGER ----

Jeg lagde ikke mærke til, at i det forventede output blev afd.nr. 10 opdateret til 20,
for at opdatere afd.nr. en anden forespørgsel er nødvendig:

UPDATE emp
   SET deptno = 20
WHERE deptno = 10;



---- REDIGER -----

Hvis du vil indsætte ændrede værdier i den anden tabel, så prøv en procedure med RETURNING..BULK COLLECT og 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 burde fungere, hvis du ikke skal behandle et stort antal poster i et opkald (mere end 1000 ... eller højst et par tusinde). Hvis man dept_id kan indeholde ti tusinde og flere rækker, så kan denne procedure være langsom, fordi den vil forbruge en enorm mængde PGA-hukommelse. I et sådant tilfælde kræves en anden tilgang med masseindsamling i bidder.

-- EDIT --- hvordan man gemmer sekvensværdier -------

Jeg antager, at tabellen ændret har 4 kolonner, som denne:

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

og vi gemmer sekvensværdier i seq_nextval kolonne.

I et sådant tilfælde kan proceduren se sådan ud:

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 til små datasæt -----

Ja, for små sæt data giver bulk-indsamling ikke en væsentlig forøgelse af hastigheden, og almindelig markør med for..loop er tilstrækkelig i et sådant tilfælde.
Nedenfor er et eksempel hvordan du bruger markøren sammen med opdatering, læg mærke til TIL OPDATERING klausul, er det påkrævet, når vi planlægger at opdatere en post hentet fra markøren ved hjælp af WHERE CURRENT OF klausul.
Denne gang evalueres en sekvensværdi i INSERT-sætningen.

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. Hvorfor returnerer AES_DECRYPT null?

  2. Konverter objekt, der indeholder gentagne felter, til JSON

  3. Sådan opretter du forbindelse til MySQL, der kører på Docker fra værtsmaskinen

  4. hvordan man ændrer størrelsen på en kolonne