Utilisation des enregistrements et des curseurs

Le contenu du script de cette page a pour seul objectif la navigation et n'altère en rien le contenu.

Vous pouvez stocker des valeurs de données dans des enregistrements et utiliser un curseur comme pointeur vers un ensemble de résultats et des informations de traitement associées.

Voir aussi : Oracle Database PL/SQL Language Reference, pour plus d'informations sur les enregistrements.

A propos des enregistrements

Un enregistrement est une variable composite PL/SQL qui peut stocker des valeurs de données de différents types. Vous pouvez traiter les composants internes (champs) comme des variables scalaires. Vous pouvez transmettre des enregistrements entiers en tant que paramètres de sous-programme. Les enregistrements peuvent contenir des données issues de lignes de table ou de certaines colonnes des lignes de table.

Un enregistrement est une variable composite PL/SQL pouvant stocker des valeurs de données de différents types, semblable à un type de structure en C, C++ ou Java. Les composants internes d'un enregistrement sont appelés champs. Pour accéder à un champ d'enregistrement, utilisez la notation par points : record_name.field_name.

Les champs d'enregistrements peuvent être traités comme des variables scalaires. Vous pouvez également transmettre des enregistrements entiers en tant que paramètres de sous-programme.

Les enregistrements peuvent contenir des données issues de lignes de table ou de certaines colonnes des lignes de table. Chaque champ d'enregistrement correspond à une colonne de table.

Vous pouvez créer un enregistrement de trois façons :

Voir aussi :

Tutoriel : Déclaration d'un type RECORD

The following steps show how to use the SQL Developer tool Edit to declare a RECORD type, sal_info, whose fields can hold salary information for an employee—job ID, minimum and maximum salary for that job ID, current salary, and suggested raise.

Etapes de déclaration du type RECORD sal_info :

  1. Dans le cadre Connexions, développez hr_conn.

    Sous l'icône hr_conn, la liste des types d'objet de schéma apparaît.

  2. Développez Packages.

    La liste des packages apparaît.

  3. Cliquez sur EMP_EVAL avec le bouton droit de la souris.

    La liste des options apparaît.

  4. Sélectionnez Modifier.

    Le panneau EMP_EVAL apparaît et affiche l'instruction CREATE PACKAGE ayant créé le 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. Dans le panneau EMP_EVAL, juste avant END EMP_EVAL, ajoutez Le code suivant :

     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) );
    

    Le titre du panneau apparaît en italique, afin d'indiquer que les modifications ne sont pas enregistrées sur la base de données.

  6. Sélectionnez l'icône Compiler.

    La spécification de package modifiée est compilée et enregistrée dans la base de données. Le titre du panneau EMP_EVAL n'apparaît plus en italique.

    Vous pouvez désormais déclarer des enregistrements du type sal_info, comme dans la rubrique "Tutorial : Creating and Invoking a Subprogram with a Record Parameter".

Tutoriel : Création et appel d'un sous-programme avec un paramètre d'enregistrement

Les étapes suivantes montrent comment utiliser l'outil SQL Developer Modifier pour créer et appeler un sous-programme avec un paramètre de type d'enregistrement sal_info.

Le type d'enregistrement sal_info a été créé dans "Tutoriel : Déclaration d'un type d'enregistrement".

Ce tutoriel indique comment utiliser l'outil SQL Developer Modifier pour effectuer les tâches suivantes :

Puisque EVAL_FREQUENCY invoquera SALARY_SCHEDULE, la déclaration de SALARY_SCHEDULE doit être antérieure à celle de EVAL_FREQUENCY (sinon, le package ne pourra pas été compilé). Toutefois, la définition de SALARY_SCHEDULE peut figurer à n'importe quel endroit du corps du package.

Etapes de création de SALARY_SCHEDULE et de modification de EVAL_FREQUENCY :

  1. Dans le cadre Connexions, développez hr_conn.

  2. Dans la liste des types d'objet de schéma, développez Packages.

  3. Dans la liste des packages, développez EMP_EVAL.

  4. Dans la liste des choix, cliquez avec le bouton droit de la souris sur Corps EVAL_EMP.

  5. Dans la liste des choix, sélectionnez Modifier.

    Le panneau Corps EMP_EVAL apparaît avec le code du corps du package.

  6. Dans le panneau EMP_EVAL Body, juste avant END EMP_EVAL, ajoutez l'expression suivante de la procédure 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;
    

    Le titre du panneau apparaît en italique, afin d'indiquer que les modifications ne sont pas enregistrées sur la base de données.

  7. Dans le volet Corps EMP_EVAL, saisissez la fonction eval_frequency et les procédures salary_schedule et add_eval à la position suivante :

     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. Modifiez la fonction EVAL_FREQUENCY en procédant comme suit :

     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. Sélectionnez Compiler.

A propos des curseurs

Lorsqu'Oracle Database exécute une instruction SQL, il stocke l'ensemble de résultats et les informations de traitement dans une zone SQL privée sans nom. Un pointeur vers cette zone sans nom, appelé curseur, permet d'extraire l'ensemble de résultats ligne par ligne. Les attributs du Curseur renvoient des informations concernant l'état du Curseur.

Chaque fois que vous exécutez une instruction SQL DML ou une instruction PL/SQL SELECT INTO, PL/SQL ouvre un curseur implicite. Vous pouvez obtenir des informations sur ce curseur à l'aide de ses attributs, mais vous ne pouvez pas le contrôler. Après l'exécution de l'instruction, la base de données ferme le curseur. Toutefois, ses valeurs d'attribut restent disponibles jusqu'à l'exécution d'une autre instruction DML ou SELECT INTO.

Le langage PL/SQL permet également de déclarer des curseurs. Un curseur déclaré porte un nom et est associé à une requête (instruction SQL SELECT), qui renvoie généralement plusieurs lignes. Après avoir déclaré un curseur, vous devez le traiter, implicitement ou explicitement. Pour traiter le curseur implicitement, utilisez un curseur FOR LOOP. La syntaxe est la suivante :

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

Pour traiter explicitement le curseur, ouvrez-le (avec l'instruction OPEN), extrayez les lignes de l'ensemble de résultats une par une ou en masse (avec l'instruction FETCH) et fermez le curseur (avec l'instruction CLOSE). Suite à la fermeture du curseur, vous ne pouvez plus extraire les enregistrements de l'ensemble de résultats, ni visualiser les valeurs des attributs du curseur.

La valeur d'un attribut de curseur implicite est SQL%attribute (par exemple, SQL%FOUND). SQL%attribute fait toujours référence à la toute dernière instruction DML ou SELECT INTO exécutée.

La valeur d'un attribut de curseur déclaré respecte la syntaxe curseur_name%attribute (par exemple, c1%FOUND). Le tableau 1 dresse la liste des attributs de curseurs et des valeurs qu'ils peuvent renvoyer. (Les curseurs implicites disposent d'attributs supplémentaires non traités par le présent manuel.)

Table 1 - Valeurs d'attribut de curseur

Attribut Valeurs pour le curseur déclaré Valeurs pour un curseur implicite
%TROUVÉ

Si le curseur est ouvert (note de bas de page 1) sans tentative d'extraction, NULL.

Si la dernière extraction a renvoyé une ligne, TRUE.

Si la dernière extraction n'a renvoyé pas de ligne, FALSE.

Si aucune instruction SELECT INTO ou DML n'a été exécutée, NULL.

Si la dernière instruction DML ou SELECT INTO a renvoyé une ligne, TRUE.

Si la dernière instruction DML ou SELECT INTO n'a renvoyé pas de ligne, FALSE.

%INTROUVABLE

Si le curseur est ouvert (note de bas de page 1) sans tentative d'extraction, NULL.

Si la dernière extraction a renvoyé une ligne, FALSE.

Si la dernière extraction n'a renvoyé pas de ligne, TRUE.

Si aucune instruction SELECT INTO ou DML n'a été exécutée, NULL.

Si la dernière instruction SELECT INTO ou DML a renvoyé une ligne, FALSE.

Si la dernière instruction DML ou SELECT INTO n'a renvoyé pas de ligne, TRUE.

%NOMBRE DE LIGNES Si le curseur est ouvert (note de bas de page 1), un nombre supérieur ou égal à zéro. NULL si aucune instruction DML ou SELECT INTO n'a été exécutée ; sinon, un nombre supérieur ou égal à zéro.
% OUVERT Si le curseur est ouvert, TRUE ; sinon, FALSE. Toujours FALSE.

Note de bas de page 1 : si le curseur n'est pas ouvert, l'attribut génère l'exception prédéfinie INVALID_CURSOR.

Voir aussi :

Utilisation d'un curseur déclaré pour extraire les lignes d'un ensemble de résultats, une à la fois

Vous pouvez utiliser un curseur déclaré pour extraire les lignes d'ensemble de résultats une par une.

La procédure suivante utilise chaque instruction nécessaire dans sa forme la plus simple, mais fournit les références correspondantes avec la syntaxe complète.

Etapes à suivre pour utiliser un curseur déclaré afin d'extraire les lignes d'ensemble de résultats une par une :

  1. Dans la partie de déclaration, effectuez les opérations suivantes :

    1. Déclarez le curseur :

       CURSOR cursor_name IS query;
      

      Pour connaître la syntaxe complète des déclarations de curseurs déclarés, reportez-vous à Oracle Database PL/SQL Language Reference.

    2. Déclarez un enregistrement pouvant contenir la ligne renvoyée par le curseur :

       record_name cursor_name%ROWTYPE;
      

      Pour connaître la syntaxe complète de %ROWTYPE, reportez-vous au guide Oracle Database PL/SQL Language Reference.

  2. Dans la partie d'exécution, effectuez les opérations suivantes :

    1. Ouvrez le curseur :

       OPEN cursor_name;
      

      Pour connaître la syntaxe complète de l'instruction OPEN, reportez-vous au guide Oracle Database PL/SQL Language Reference.

    2. Extrayez, une par une, les lignes du curseur (lignes de l'ensemble de résultats) à l'aide d'une instruction LOOP dont le code est semblable à celui qui suit :

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

      Pour connaître la syntaxe complète de l'instruction FETCH, reportez-vous au guide Oracle Database PL/SQL Language Reference.

    3. Fermez le curseur :

       CLOSE cursor_name;
      

Pour connaître la syntaxe complète de l'instruction CLOSE, reportez-vous au guide Oracle Database PL/SQL Language Reference.

Tutoriel : Utilisation d'un curseur de curseur pour extraire les lignes de l' ensemble de résultats, une à la fois

Les étapes suivantes montrent comment implémenter la procédure EMP_EVAL.EVAL_DEPARTMENT, qui utilise un curseur déclaré, emp_cursor.

Pour implémenter la procédure EMP_EVAL.EVAL_DEPARTMENT, procédez comme suit :

  1. Dans la spécification de package EMP_EVAL, modifiez la déclaration de la procédure EVAL_DEPARTMENT comme indiqué :

     PROCEDURE eval_department(dept_id IN employees.department_id%TYPE);
    
  2. Dans le corps de package EMP_EVAL, modifiez la définition de la procédure EVAL_DEPARTMENT comme indiqué en caractères gras dans l'exemple suivant :

     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;
    

    (Pour obtenir un exemple étape par étape de la modification du corps d'un package, reportez-vous à la section "Tutorial : Declaring Variables and Constants in a Subprogram".)

  3. Compilez la spécification de package EMP_EVAL.

  4. Compilez le corps de package EMP_EVAL.

A propos des variables de curseur

Une variable de curseur est semblable à un curseur, mais elle n'est pas limitée à une seule requête. Vous pouvez ouvrir une variable de curseur pour une requête, traiter l'ensemble de résultats, puis utiliser la variable de curseur pour une autre requête. Les variables de curseur permettent la transmission de résultats de requête entre les sous-programmes.

Pour plus d'informations sur les curseurs, reportez-vous à la section "A propos des curseurs".

Pour déclarer une variable de curseur, déclarez un type REF CURSOR, puis déclarez une variable de ce type (par conséquent, les variable de curseur est souvent appelées REF CURSOR). Un type REF CURSOR peut être fort ou faible.

Le type de renvoi REF CURSOR indique un type de renvoi, qui correspond au type ENREGISTREMENT de ses variables du curseur. Le compilateur PL/SQL ne permet pas l'utilisation de ces variables du curseur de type Fort pour les requêtes qui renvoient les lignes qui ne correspondent pas au type de renvoi. Les types REF CURSOR forts engendrent moins d'erreurs que le type faible, mais les type faibles sont plus flexibles.

La forme de faible du type REF CURSOR n'indique aucun type de renvoi. Le compilateur PL/SQL accepte les variables de curseur de type faible dans toutes les requêtes. Les types REF CURSOR faibles sont interchangeables. Ainsi, au lieu de créer des types REF CURSOR faibles, vous pouvez utiliser le type de curseur faible prédéfini SYS_REFCURSOR.

Après avoir déclaré une variable de curseur, vous devez l'ouvrir pour une requête spécifique (à l'aide de l'instruction OPEN FOR), extraire les lignes de l'ensemble des résultats une par un (à l'aide de l'instruction FETCH), puis fermer le curseur (à l'aide de l'instruction CLOSE) ou l'ouvrir pour une autre requête spécifique (à l'aide de l'instruction OPEN FOR). L'ouverture de la variable de curseur pour une autre requête la ferme pour la requête précédente. Suite à la fermeture du curseur pour une requête spécifique, vous ne pouvez plus extraire les enregistrements de l'ensemble de résultats de cette requête, ni visualiser les valeurs des attributs du curseur.

Voir aussi :

Utilisation d'une variable de curseur pour extraire les lignes de l'ensemble de résultats, une à la fois

Vous pouvez utiliser une variable de curseur pour extraire les lignes de l'ensemble de résultats une par une.

La procédure suivante utilise chaque instruction nécessaire dans sa forme la plus simple, mais fournit les références correspondantes à la syntaxe complète.

Procédure d'utilisation d'une variable de curseur pour extraire les lignes d'un ensemble de résultats une par une :

  1. Dans la partie de déclaration, effectuez les opérations suivantes :

    1. Déclarez le type REF CURSOR :

       TYPE cursor_type IS REF CURSOR [ RETURN return_type ];
      

      Pour connaître le syntaxe complète des déclaration de type REF CURSOR, reportez-vous au manuelOracle Database PL/SQL Language Reference.

    2. Déclarez une variable de curseur de ce type :

       cursor_variable cursor_type;
      

      Pour connaître la syntaxe complète des déclarations de variable de curseur, reportez-vous au guide Oracle Database PL/SQL Language Reference.

    3. Déclarez un enregistrement pouvant contenir la ligne renvoyée par le curseur :

       record_name return_type;
      

      Pour obtenir des informations complètes sur la syntaxe des déclaration d'enregistrements, reportez-vous au guide Oracle Database PL/SQL Language Reference.

  2. Dans la partie d'exécution, effectuez les opérations suivantes :

    1. Ouvrez la variable de curseur pour une requête spécifique :

       OPEN cursor_variable FOR query;
      

      Pour plus d'informations sur la syntaxe de l'instruction OPEN FOR, reportez-vous au guide Oracle Database PL/SQL Language Reference.

    2. Extrayez, une par une, les lignes de la variable du curseur (lignes de l'ensemble de résultats) à l'aide d'une instruction LOOP dont le syntaxe ressemble à l'exemple suivant :

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

      Pour plus d'informations sur la syntaxe de l'instruction FETCH, reportez-vous au guide Oracle Database PL/SQL Language Reference.

    3. Fermez la variable de curseur :

       CLOSE cursor_variable;
      

      Vous pouvez également ouvrir la variable de curseur pour une autre requête, ce qui la ferme pour la requête en cours.

      Pour plus d'informations sur la syntaxe de l'instruction CLOSE, reportez-vous au guide Oracle Database PL/SQL Language Reference.

Tutoriel : Utilisation d'une variable de curseur pour extraire les lignes de l'ensemble de résultats, une à la fois

Les étapes suivantes montrent comment modifier la procédure EMP_EVAL.EVAL_DEPARTMENT afin qu'elle utilise une variable de curseur au lieu d'un curseur déclaré (qui lui permet de traiter plusieurs services) et comment rendre EMP_EVAL.EVAL_DEPARTMENT et EMP_EVAL.ADD_EVAL plus efficaces.

Ce tutoriel présente également l'optimisation des procédures EMP_EVAL.EVAL_DEPARTMENT et EMP_EVAL.ADD_EVAL : au lieu de transmettre un champ d'un enregistrement à ADD_EVAL et que ADD_EVAL utilise trois autres champs du même enregistrement afin d'extraire trois autres champs, EVAL_DEPARTMENT transmet l'enregistrement entier à ADD_EVAL et ADD_EVAL utilise la notation par points pour accéder aux valeurs des trois autres champs.

Pour modifier la procédure EMP_EVAL.EVAL_DEPARTMENT afin d'utiliser une variable du curseur, procédez Comme suit :

  1. Dans la spécification de package EMP_EVAL, ajoutez la déclaration et la définition de type REF CURSOR comme indiqué en caractères gras dans l'exemple suivant :

     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. Dans le corps de package EMP_EVAL, ajoutez une déclaration anticipée pour la procédure EVAL_LOOP_CONTROL et modifiez la déclaration de la procédure ADD_EVAL comme indiqué en caractères gras.

     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);
     ...
    

    (Pour obtenir un exemple étape par étape de la modification du corps d'un package, reportez-vous à la section "Tutorial : Declaring Variables and Constants in a Subprogram".)

  3. Modifiez la procédure EVAL_DEPARTMENT pour extraire trois ensembles de résultats distincts en fonction du service et appeler la procédure EVAL_LOOP_CONTROL comme indiqué en caractères gras dans l'exemple suivant :

     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. Modifiez la procédure ADD_EVAL comme indiqué ci-dessous :

     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. Avant END EMP_EVAL, ajoutez la procédure suivante qui extrait les enregistrements individuels de l'ensemble de résultats et les traite :

     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. Avant END EMP_EVAL, ajoutez la procédure suivante qui extrait l'ensemble de résultats contenant l'ensemble des employés de la société :

     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. Compilez la spécification de package EMP_EVAL.

  8. Compilez le corps de package EMP_EVAL.