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 AI 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.

TYPE record_name IS RECORD
  ( field_name data_type [:= initial_value]
 [, field_name data_type [:= initial_value ] ]... );

variable_name record_name;

Vedere anche:

Esercitazione: Dichiarazione di un tipo RECORD

Questa esercitazione mostra come utilizzare lo strumento Modifica Di SQL Developer per dichiarare un tipo RECORD, sal_info, i cui campi possono contenere le informazioni sugli stipendi per un dipendente (ID mansione, stipendio minimo e massimo per l'ID mansione, stipendio corrente e aumento suggerito).

Per dichiarare il tipo 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. Fare clic su 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. Fare clic sull'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

Questa esercitazione mostra 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 eseguire le operazioni riportate 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.

Per creare SALARY_SCHEDULE e modificare EVAL_FREQUENCY, procedere come segue.

  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 fare clic su Modifica.

    Viene visualizzato il 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 questa 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 il codice mostrato in grassetto nella posizione seguente:

    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 mostrate in grassetto:

    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. Fare clic su Compila.

Informazioni sui cursori

Quando viene eseguita un'istruzione SQL, il database memorizza il set di risultati e l'elaborazione delle informazioni 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 SQL DML o un'istruzione PL/SQL SELECT INTO, 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 5-1 elenca gli attributi del cursore e i valori che possono restituire. (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, ma non si è eseguita 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, ma non si è eseguita 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, 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.

Per gli attributi %FOUND, %NOTFOUND e %ROWCOUNT, 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.

Per utilizzare il 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 una sintassi dichiarata completa della dichiarazione del cursore, vedere Oracle AI 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 AI 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 AI Database PL/SQL Language Reference.

    2. Recuperare le righe dal cursore (righe del set di risultati) una alla volta utilizzando un'istruzione LOOP con una sintassi simile alla 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 AI Database PL/SQL Language Reference.

    3. Chiudere il cursore:

      CLOSE cursor_name;

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

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

Questa esercitazione mostra come implementare la procedura EMP_EVAL.EVAL_DEPARTMENT, che utilizza un cursore dichiarato, emp_cursor.

Per implementare la procedura EMP_EVAL.EVAL_DEPARTMENT, effettuare le operazioni riportate di seguito.

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

    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.

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 AI 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 AI 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 AI 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 AI 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 AI 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 AI Database PL/SQL Language Reference.

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

Questa esercitazione mostra come modificare la procedura EMP_EVAL.EVAL_DEPARTMENT in modo che utilizzi una variabile di cursore anziché un cursore dichiarato (che consente di elaborare più reparti) e come consentire l'elaborazione di più dipartimenti 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.

Per modificare la procedura EMP_EVAL.EVAL_DEPARTMENT in modo che utilizzi una variabile di cursore, procedere come segue.

  1. Nella specifica package EMP_EVAL aggiungere la dichiarazione della procedura e la definizione del tipo REF CURSOR, come mostrato in grassetto:

    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 grassetto:

    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 l'operazione EVAL_LOOP_CONTROL, come mostrato in grassetto:

    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 mostrato in grassetto:

    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.