Uso di record e cursori

I componenti script in questa pagina sono utilizzati solo per scopi di navigazione e non alterano in alcun modo il contenuto.

È possibile memorizzare i valori dei dati nei record e utilizzare un cursore come puntatore a un set di risultati e alle informazioni di elaborazione correlate.

Per ulteriori informazioni sui record, vedere anche: Oracle Database PL/SQL Language Reference

Informazioni sui record

Un record è una variabile composta PL/SQL in grado di memorizzare valori di dati di tipi diversi. È possibile considerare i componenti interni (campi) come variabili scalari. È possibile passare interi record come parametri del sottoprogramma. I record sono utili per contenere i dati delle righe delle tabelle o di determinate colonne di righe delle tabelle.

Un record è una variabile composita PL/SQL che può memorizzare valori di dati di diversi tipi, in modo analogo al tipo struct in C, C++ o Java. I componenti interni di un record sono chiamati campi. Per accedere a un campo di un record si utilizza la notazione a punti: record_name.field_name.

È possibile trattare i campi dei record come variabili scalari. È inoltre possibile passare interi record come parametri del sottoprogramma.

I record sono utili per contenere i dati delle righe delle tabelle o di determinate colonne di righe delle tabelle. Ogni campo del record corrisponde a una colonna della tabella.

Per creare un record sono disponibili i tre modi riportati di seguito.

Vedere anche:

Esercitazione: Dichiarazione di un tipo RECORD

I passi riportati di seguito mostrano come utilizzare lo strumento Modifica SQL Developer per dichiarare un tipo RECORD, sal_info, i cui campi possono contenere le informazioni stipendio per un dipendente (ID mansione, stipendio minimo e massimo per l'ID mansione, stipendio corrente e aumento suggerito).

Passi per dichiarare il tipo di RECORD sal_info:

  1. Nel frame Connessioni espandere hr_conn.

    Sotto l'icona hr_conn viene visualizzata una lista di tipi d'oggetto dello schema.

  2. Espandere Package.

    Viene visualizzata una lista di package.

  3. fare clic con il pulsante destro del mouse su EMP_EVAL.

    Viene visualizzata una lista di scelte.

  4. Selezionare Modifica.

    Viene aperto il riquadro EMP_EVAL, in cui è riportata l'istruzione CREATE PACKAGE che ha creato il package:

    CREATE OR REPLACE PACKAGE EMP_EVAL AS
       
    PROCEDURE eval_department(dept_id IN NUMBER);
    FUNCTION calculate_score(evaluation_id IN NUMBER
                           , performance_id IN NUMBER)
                             RETURN NUMBER;
       
    END EMP_EVAL;
    
  5. Nel riquadro EMP_EVAL, immediatamente prima di END EMP_EVAL, aggiungere questo codice:

     TYPE sal_info IS RECORD
       ( j_id     jobs.job_id%type
       , sal_min  jobs.min_salary%type
       , sal_max  jobs.max_salary%type
       , sal      employees.salary%type
       , sal_raise NUMBER(3,3) );
    

    Il titolo del riquadro è in corsivo, a significare che le modifiche non sono state salvate nel database.

  6. Selezionare l'icona Compila.

    La specifica package modificata viene compilata e salvata nel database. Il titolo del riquadro EMP_EVAL non è più in corsivo.

    Ora è possibile dichiarare i record di tipo sal_info, come in "Esercitazione: Creazione e richiamo del sottoprogramma con un parametro record".

Esercitazione: Creazione e richiamo di un sottoprogramma con un parametro record

I passi riportati di seguito mostrano come utilizzare lo strumento Modifica di SQL Developer per creare e richiamare un sottoprogramma con un parametro del tipo di record sal_info.

Il tipo di RECORD sal_info è stato creato in "Esercitazione: dichiarazione di un tipo di RECORD".

Questa esercitazione mostra come utilizzare lo strumento Modifica di SQL Developer per completare i task riportati di seguito.

Poiché EVAL_FREQUENCY richiama SALARY_SCHEDULE, la dichiarazione di SALARY_SCHEDULE deve precedere la dichiarazione di EVAL_FREQUENCY (altrimenti il package non viene compilato). Tuttavia, la definizione di SALARY_SCHEDULE può trovarsi in qualsiasi punto del package body.

Passi per creare SALARY_SCHEDULE e modificare EVAL_FREQUENCY:

  1. Nel frame Connessioni espandere hr_conn.

  2. Nella lista dei tipi di oggetto schema espandere Pacchetti.

  3. Nell'elenco dei pacchetti espandere EMP_EVAL.

  4. Nell'elenco delle opzioni, fare clic con il pulsante destro del mouse su Corpo EMP_EVAL.

  5. Nell'elenco di scelte, selezionare Modifica.

    Viene visualizzato un riquadro Corpo EMP_EVAL, in cui è mostrato il codice per il package body.

  6. Nel riquadro Corpo EMP_EVAL, immediatamente prima di END EMP_EVAL, aggiungere una definizione della procedura SALARY_SCHEDULE:

     PROCEDURE salary_schedule (emp IN sal_info) AS
       accumulating_sal  NUMBER;
     BEGIN
       DBMS_OUTPUT.PUT_LINE('If salary ' || emp.sal ||
         ' increases by ' || ROUND((emp.sal_raise * 100),0) ||
    
         '% each year, it will be:');
    
       accumulating_sal := emp.sal;
    
       WHILE accumulating_sal <= emp.sal_max LOOP
         accumulating_sal := accumulating_sal * (1 + emp.sal_raise);
         DBMS_OUTPUT.PUT_LINE(ROUND(accumulating_sal,2) ||', ');
    
       END LOOP;
     END salary_schedule;
    

    Il titolo del riquadro è in corsivo, a significare che le modifiche non sono state salvate nel database.

  7. Nel riquadro Corpo EMP_EVAL, immettere la funzione eval_frequency e le procedure stipendio_schedule e add_eval nella seguente posizione:

     CREATE OR REPLACE
     PACKAGE BODY EMP_EVAL AS
    
     FUNCTION eval_frequency (emp_id EMPLOYEES.EMPLOYEE_ID%TYPE)
    
       RETURN PLS_INTEGER;
    
     PROCEDURE salary_schedule(emp IN sal_info);
    
     PROCEDURE add_eval(employee_id IN employees.employee_id%type, today IN DATE);
    
     PROCEDURE eval_department (dept_id IN NUMBER) AS
    
  8. Modificare la funzione EVAL_FREQUENCY apportando le modifiche riportate di seguito.

     FUNCTION eval_frequency (emp_id EMPLOYEES.EMPLOYEE_ID%TYPE)
       RETURN PLS_INTEGER
     AS
       h_date     EMPLOYEES.HIRE_DATE%TYPE;
       today      EMPLOYEES.HIRE_DATE%TYPE;
       eval_freq  PLS_INTEGER;
    
       emp_sal    SAL_INFO;  -- replaces sal, sal_raise, and sal_max
    
     BEGIN
       SELECT SYSDATE INTO today FROM DUAL;
    
       SELECT HIRE_DATE INTO h_date
       FROM EMPLOYEES
       WHERE EMPLOYEE_ID = eval_frequency.emp_id;
    
       IF ((h_date + (INTERVAL '120' MONTH)) < today) THEN
         eval_freq := 1;
    
         /* populate emp_sal */
    
         SELECT j.JOB_ID, j.MIN_SALARY, j.MAX_SALARY, e.SALARY
    
         INTO emp_sal.j_id, emp_sal.sal_min, emp_sal.sal_max, emp_sal.sal
    
         FROM EMPLOYEES e, JOBS j
    
         WHERE e.EMPLOYEE_ID = eval_frequency.emp_id
    
         AND j.JOB_ID = eval_frequency.emp_id;
    
         emp_sal.sal_raise := 0;  -- default
    
         CASE emp_sal.j_id
           WHEN 'PU_CLERK' THEN emp_sal.sal_raise := 0.08;
           WHEN 'SH_CLERK' THEN emp_sal.sal_raise := 0.07;
           WHEN 'ST_CLERK' THEN emp_sal.sal_raise := 0.06;
           WHEN 'HR_REP' THEN emp_sal.sal_raise := 0.05;
           WHEN 'PR_REP' THEN emp_sal.sal_raise := 0.05;
           WHEN 'MK_REP' THEN emp_sal.sal_raise := 0.04;
           ELSE NULL;
         END CASE;
    
         IF (emp_sal.sal_raise != 0) THEN
    
           salary_schedule(emp_sal);
         END IF;
       ELSE
         eval_freq := 2;
       END IF;
    
       RETURN eval_freq;
     END eval_frequency;
    
  9. Selezionare Compila.

Informazioni sui cursori

Quando viene eseguita un'istruzione SQL, Oracle Database memorizza il set di risultati e i dati di elaborazione in un'area SQL privata senza nome. Un puntatore a tale area senza nome, denominato cursore, consente di recuperare il set di risultati una riga alla volta. Gli attributi del cursore restituiscono le informazioni sullo stato del cursore.

Ogni volta che si esegue un'istruzione DML SQL o un'istruzione SELECT INTO PL/SQL, PL/SQL apre un cursore implicito. È possibile ottenere informazioni su questo cursore dai relativi attributi, ma non è possibile controllarli. In seguito all'esecuzione dell'istruzione, il database chiude il cursore; tuttavia, i valori degli attributi restano disponibili fino a quando non viene eseguita un'altra istruzione DML o SELECT INTO.

PL/SQL consente anche di dichiarare cursori. Un cursore dichiarato ha un nome ed è associato a una Query (istruzione SQL SELECT), solitamente una Query che restituisce più righe. Dopo aver dichiarato un cursore, è necessario elaborarlo, implicitamente o esplicitamente. Per elaborare il cursore in modo implicito, utilizzare un cursore FOR LOOP. La sintassi è:

FOR record_name IN cursor_name LOOP
  statement
  [ statement ]...
END LOOP;

Per elaborare il cursore in modo esplicito, aprirlo (con l'istruzione OPEN), recuperare le righe dal set di risultati uno alla volta o in blocco (con l'istruzione FETCH) e chiudere il cursore (con l'istruzione CLOSE). Dopo aver chiuso il cursore, non è possibile recuperare i record dal set di risultati né vedere i valori degli attributi del cursore.

La sintassi per il valore di un attributo del cursore implicito è SQL%attribute (ad esempio, SQL%FOUND). SQL%attribute fa sempre riferimento all'ultima istruzione DML o SELECT INTO eseguita.

La sintassi per il valore dell'attributo di cursore dichiarato è cursor_name%attribute (ad esempio, c1%FOUND). La tabella 1 elenca gli attributi e i valori che possono restituire il cursore. (i cursori impliciti hanno attributi aggiuntivi che non vengono descritti in questo manuale).

Tabella 1 - Valori attributo cursore

Attributo Valori per cursore dichiarato Valori per il cursore implicito
% TROVATO

Se il cursore è aperto (nota a piè di pagina 1) ma non si è tentata alcuna operazione di fetch, NULL.

Se l'operazione di FETCH più recente ha restituito una riga, TRUE.

Se l'operazione di fetch più recente non ha restituito una riga, FALSE.

Se non è stata eseguita alcuna istruzione DML o SELECT INTO, NULL.

Se l'istruzione DML o SELECT INTO più recente ha restituito una riga, TRUE.

Se l'istruzione DML o SELECT INTO più recente non ha restituito una riga, FALSE.

%NON TROVATO

Se il cursore è aperto (nota a piè di pagina 1) ma non si è tentata alcuna operazione di fetch, NULL.

Se l'operazione di FETCH più recente ha restituito una riga, FALSE.

Se l'operazione di fetch più recente non ha restituito una riga, TRUE.

Se non è stata eseguita alcuna istruzione DML o SELECT INTO, NULL.

Se l'istruzione DML o SELECT INTO più recente ha restituito una riga, FALSE.

Se l'istruzione DML o SELECT INTO più recente non ha restituito una riga, TRUE.

% CONTEGGIO RIGHE Se il cursore è aperto (nota a piè di pagina 1), un numero maggiore o uguale a zero. NULL se non è stata eseguita alcuna istruzione DML o SELECT INTO; altrimenti, un numero superiore o uguale a zero.
%SOPEN Se il cursore è aperto, TRUE; in caso contrario, FALSE. Sempre FALSO.

Nota a piè di pagina 1: se il cursore non è aperto, l'attributo genera l'eccezione predefinita INVALID_CURSOR.

Vedere anche:

Utilizzo di un cursore dichiarato per recuperare le righe del set di risultati una alla volta

È possibile utilizzare un cursore dichiarato per recuperare le righe del set di risultati una alla volta.

La procedura seguente utilizza ogni istruzione necessaria nella forma più semplice, ma fornisce i riferimenti alla sintassi completa.

Passi per utilizzare un cursore dichiarato per recuperare le righe del set di risultati una alla volta:

  1. Nella parte dichiarativa:

    1. Dichiarare il cursore:

       CURSOR cursor_name IS query;
      

      Per la sintassi completa di dichiarazione di cursore dichiarata, vedere Oracle Database PL/SQL Language Reference.

    2. Dichiarare un record per contenere la riga restituita dal cursore.

       record_name cursor_name%ROWTYPE;
      

      Per completare la sintassi %ROWTYPE, vedere Oracle Database PL/SQL Language Reference.

  2. Nella parte eseguibile:

    1. Aprire il cursore:

       OPEN cursor_name;
      

      Per la sintassi completa dell'istruzione OPEN, vedere Oracle Database PL/SQL Language Reference.

    2. Recupera le righe dal cursore (righe del set di risultati) una alla volta utilizzando un'istruzione LOOP con una sintassi simile al seguente:

       LOOP
         FETCH cursor_name INTO record_name;
         EXIT WHEN cursor_name%NOTFOUND;
      
         -- Process row that is in record_name:
      
         statement;
         [ statement; ]...
       END LOOP;
      

      Per la sintassi completa dell'istruzione FETCH, vedere Oracle Database PL/SQL Language Reference.

    3. Chiudere il cursore:

       CLOSE cursor_name;
      

Per la sintassi completa dell'istruzione CLOSE, vedere Oracle Database PL/SQL Language Reference.

Esercitazione: Utilizzo di un cursore dichiarato per recuperare le righe del set di risultati una alla volta

I passaggi seguenti mostrano come implementare la procedura EMP_EVAL.EVAL_DEPARTMENT, che utilizza un cursore dichiarato, emp_cursor.

Per implementare la procedura EMP_EVAL.EVAL_DEPARTMENT, procedere come segue.

  1. Nella specifica package EMP_EVAL modificare la dichiarazione della procedura EVAL_DEPARTMENT come mostrato in basso:

     PROCEDURE eval_department(dept_id IN employees.department_id%TYPE);
    
  2. Nel package body EMP_EVAL modificare la definizione della procedura EVAL_DEPARTMENT come mostrato in grassetto.

     PROCEDURE eval_department (dept_id IN employees.department_id%TYPE)
     AS
    
       CURSOR emp_cursor IS
    
         SELECT * FROM EMPLOYEES
    
         WHERE DEPARTMENT_ID = eval_department.dept_id;
    
       emp_record  EMPLOYEES%ROWTYPE;  -- for row returned by cursor
    
       all_evals   BOOLEAN;  -- true if all employees in dept need evaluations
    
       today       DATE;
    
     BEGIN
    
       today := SYSDATE;
    
       IF (EXTRACT(MONTH FROM today) < 6) THEN
    
         all_evals := FALSE; -- only new employees need evaluations
    
       ELSE
    
         all_evals := TRUE;  -- all employees need evaluations
    
       END IF;
    
       OPEN emp_cursor;
    
       DBMS_OUTPUT.PUT_LINE (
    
         'Determining evaluations necessary in department # ' ||
    
         dept_id );
    
       LOOP
    
         FETCH emp_cursor INTO emp_record;
    
         EXIT WHEN emp_cursor%NOTFOUND;
    
         IF all_evals THEN
    
           add_eval(emp_record.employee_id, today);
    
         ELSIF (eval_frequency(emp_record.employee_id) = 2) THEN
    
           add_eval(emp_record.employee_id, today);
    
         END IF;
    
       END LOOP;
    
       DBMS_OUTPUT.PUT_LINE('Processed ' || emp_cursor%ROWCOUNT || ' records.');
    
       CLOSE emp_cursor;
     END eval_department;
    

    Per un esempio dettagliato di modifica di un package body, vedere "Esercitazione: Dichiarazione di variabili e costanti in un sottoprogramma".

  3. Compilare la specifica package EMP_EVAL.

  4. Compilare il package body EMP_EVAL.

Informazioni sulle variabili del cursore

Una variabile del cursore è simile a un cursore, ad eccezione del fatto che non è limitata a una query. È possibile aprire una variabile cursore per una query, elaborare il set di risultati e quindi utilizzare la variabile cursore per un'altra query. Le variabili cursore sono utili per passare il risultato delle query tra due sottoprogrammi.

Per informazioni sui cursori, vedere "Informazioni sui cursori".

Per dichiarare una variabile del cursore, è necessario dichiarare un tipo REF CURSOR e quindi dichiarare una variabile del tipo specificato (pertanto, una variabile del cursore viene spesso chiamata REF CURSOR). Un tipo REF CURSOR può essere forte o debole.

Un tipo REF CURSOR forte specifica un tipo restituito , che rappresenta il tipo RECORD delle relative variabili del cursore. Il compilatore PL/SQL non consente di utilizzare queste variabili del cursore forti per le query che restituiscono righe diverse dal tipo restituito. I tipi REF CURSOR forti sono meno inclini agli errori rispetto ai modelli deboli, ma questi ultimi sono più flessibili.

Un tipo REF CURSOR debole non specifica un tipo restituito. Il compilatore PL/SQL accetta variabili del cursore deboli in qualsiasi query. I tipi CURSOR REF deboli sono intercambiabili; pertanto, invece di creare tipi REF CURSOR deboli, è possibile utilizzare il tipo di cursore debole tipo predefinito SYS_REFCURSOR.

Dopo aver dichiarato una variabile cursore, è necessario aprirla per una query specifica (con l'istruzione OPEN FOR), recuperare le righe una alla volta dal set di risultati (con l'istruzione FETCH) e quindi chiudere il cursore (con l'istruzione CLOSE) o aprirlo per un'altra query specifica (con l'istruzione OPEN FOR). L'apertura della variabile cursore per un'altra query ne determina la chiusura per la query precedente. Dopo aver chiuso una variabile cursore per una query specifica, non è possibile recuperare i record dal set di risultati della query né vedere i valori degli attributi del cursore per la query.

Vedere anche:

Uso di una variabile del cursore per recuperare le righe del set di risultati una alla volta

Per recuperare le righe del set di risultati una alla volta, è possibile utilizzare una variabile cursore.

La procedura riportata di seguito utilizza ogni istruzione necessaria nella forma più semplice, ma fornisce i riferimenti alla sintassi completa.

Passi per utilizzare una variabile cursore per recuperare le righe del set di risultati una alla volta:

  1. Nella parte dichiarativa:

    1. Dichiarare il tipo REF CURSOR:

       TYPE cursor_type IS REF CURSOR [ RETURN return_type ];
      

      Per la sintassi completa della dichiarazione di tipo REF CURSOR, vedere Oracle Database PL/SQL Language Reference.

    2. Dichiarare una variabile di cursore del tipo specificato:

       cursor_variable cursor_type;
      

      Per la sintassi completa della dichiarazione delle variabili del cursore, vedere Oracle Database PL/SQL Language Reference.

    3. Dichiarare un record per contenere la riga restituita dal cursore.

       record_name return_type;
      

      Per informazioni complete sulla sintassi delle dichiarazioni del record, vedere Oracle Database PL/SQL Language Reference.

  2. Nella parte eseguibile:

    1. Aprire la variabile del cursore per una query specifica:

       OPEN cursor_variable FOR query;
      

      Per informazioni complete sulla sintassi dell'istruzione OPEN FOR, vedere Oracle Database PL/SQL Language Reference.

    2. Recupera le righe dalla variabile del cursore (righe del set di risultati) una alla volta, utilizzando un'istruzione LOOP che ha una sintassi simile alla seguente:

       LOOP
         FETCH cursor_variable INTO record_name;
         EXIT WHEN cursor_variable%NOTFOUND;
      
         -- Process row that is in record_name:
      
         statement;
         [ statement; ]...
       END LOOP;
      

      Per informazioni complete sulla sintassi dell'istruzione FETCH, vedere Oracle Database PL/SQL Language Reference.

    3. Chiudere la variabile del cursore:

       CLOSE cursor_variable;
      

      In alternativa, è possibile aprire la variabile del cursore per un'altra query, determinandone così la chiusura per la query corrente.

      Per informazioni complete sulla sintassi dell'istruzione CLOSE, vedere Oracle Database PL/SQL Language Reference.

Esercitazione: Uso di una variabile del cursore per recuperare le righe del set di risultati una alla volta

Questa procedura mostra come modificare la procedura EMP_EVAL.EVAL_DEPARTMENT in modo che utilizzi una variabile del cursore anziché un cursore dichiarato (che gli consente di elaborare più reparti) e come rendere più efficienti EMP_EVAL.EVAL_DEPARTMENT e EMP_EVAL.ADD_EVAL.

Questa esercitazione dimostra come rendere più efficiente EMP_EVAL.EVAL_DEPARTMENT e EMP_EVAL.ADD_EVAL: invece di passare il campo di un record a ADD_EVAL e fare in modo che ADD_EVAL utilizzi tre query per estrarre altri tre campi dello stesso record, EVAL_DEPARTMENT passa l'intero record a ADD_EVAL e ADD_EVAL utilizza la notazione a punti per accedere ai valori degli altri tre campi.

Passi per modificare la procedura EMP_EVAL.EVAL_DEPARTMENT in modo che utilizzi una variabile di cursore:

  1. Nella specifica package EMP_EVAL aggiungere la dichiarazione della procedura e la definizione del tipo REF CURSOR, come mostrato nell'esempio riportato di seguito.

     CREATE OR REPLACE
     PACKAGE emp_eval AS
    
       PROCEDURE eval_department (dept_id IN employees.department_id%TYPE);
    
       PROCEDURE eval_everyone;
    
       FUNCTION calculate_score(eval_id IN scores.evaluation_id%TYPE
                             , perf_id IN scores.performance_id%TYPE)
                               RETURN NUMBER;
       TYPE SAL_INFO IS RECORD
           ( j_id jobs.job_id%type
           , sal_min jobs.min_salary%type
           , sal_max jobs.max_salary%type
           , salary employees.salary%type
           , sal_raise NUMBER(3,3));
    
       TYPE emp_refcursor_type IS REF CURSOR RETURN employees%ROWTYPE;
     END emp_eval;
    
  2. Nel package body EMP_EVAL aggiungere una dichiarazione di inoltro per la procedura EVAL_LOOP_CONTROL e modificare la dichiarazione della procedura ADD_EVAL, come mostrato in basso:

     CREATE OR REPLACE
     PACKAGE BODY EMP_EVAL AS
    
       FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
         RETURN PLS_INTEGER;
    
       PROCEDURE salary_schedule(emp IN sal_info);
    
       PROCEDURE add_eval(emp_record IN EMPLOYEES%ROWTYPE, today IN DATE);
    
       PROCEDURE eval_loop_control(emp_cursor IN emp_refcursor_type);
     ...
    

    Per un esempio dettagliato di modifica di un package body, vedere "Esercitazione: Dichiarazione di variabili e costanti in un sottoprogramma".

  3. Modificare la procedura EVAL_DEPARTMENT per recuperare tre set di risultati separati, in base al dipartimento, e per richiamare il processo EVAL_LOOP_CONTROL, come mostrato nell'esempio riportato di seguito.

     PROCEDURE eval_department(dept_id IN employees.department_id%TYPE) AS
    
       emp_cursor    emp_refcursor_type;
    
       current_dept  departments.department_id%TYPE;
    
     BEGIN
    
       current_dept := dept_id;
    
       FOR loop_c IN 1..3 LOOP
    
         OPEN emp_cursor FOR
    
           SELECT *
    
           FROM employees
    
           WHERE current_dept = eval_department.dept_id;
    
         DBMS_OUTPUT.PUT_LINE
           ('Determining necessary evaluations in department #' ||
    
           current_dept);
    
         eval_loop_control(emp_cursor);
    
         DBMS_OUTPUT.PUT_LINE
           ('Processed ' || emp_cursor%ROWCOUNT || ' records.');
    
         CLOSE emp_cursor;
    
         current_dept := current_dept + 10;
    
       END LOOP;
     END eval_department;
    
  4. Modificare la procedura ADD_EVAL come indicato di seguito.

     PROCEDURE add_eval(emp_record IN employees%ROWTYPE, today IN DATE)
     AS
    
     -- (Delete local variables)
     BEGIN
       INSERT INTO EVALUATIONS (
         evaluation_id,
         employee_id,
         evaluation_date,
         job_id,
         manager_id,
         department_id,
         total_score
       )
       VALUES (
         evaluations_sequence.NEXTVAL,   -- evaluation_id
    
         emp_record.employee_id,    -- employee_id
         today,                     -- evaluation_date
    
         emp_record.job_id,         -- job_id
    
         emp_record.manager_id,     -- manager_id
    
         emp_record.department_id,  -- department_id
         0                           -- total_score
     );
     END add_eval;
    
  5. Prima del END EMP_EVAL, aggiungere la seguente procedura, che recupera i singoli record dal set di risultati e li elabora:

     PROCEDURE eval_loop_control (emp_cursor IN emp_refcursor_type) AS
       emp_record      EMPLOYEES%ROWTYPE;
       all_evals       BOOLEAN;
       today           DATE;
     BEGIN
       today := SYSDATE;
    
       IF (EXTRACT(MONTH FROM today) < 6) THEN
    
         all_evals := FALSE;
       ELSE
         all_evals := TRUE;
       END IF;
    
       LOOP
         FETCH emp_cursor INTO emp_record;
         EXIT WHEN emp_cursor%NOTFOUND;
    
         IF all_evals THEN
           add_eval(emp_record, today);
         ELSIF (eval_frequency(emp_record.employee_id) = 2) THEN
    
           add_eval(emp_record, today);
         END IF;
       END LOOP;
     END eval_loop_control;
    
  6. Prima del END EMP_EVAL aggiungere la seguente procedura, che recupera un set di risultati contenente tutti i dipendenti nella società:

     PROCEDURE eval_everyone AS
       emp_cursor emp_refcursor_type;
     BEGIN
       OPEN emp_cursor FOR SELECT * FROM employees;
       DBMS_OUTPUT.PUT_LINE('Determining number of necessary evaluations.');
       eval_loop_control(emp_cursor);
       DBMS_OUTPUT.PUT_LINE('Processed ' || emp_cursor%ROWCOUNT || ' records.');
       CLOSE emp_cursor;
     END eval_everyone;
    
  7. Compilare la specifica package EMP_EVAL.

  8. Compilare il package body EMP_EVAL.