Utilisation d'enregistrements et de curseurs

Le contenu du script de cette page est destiné uniquement à la navigation et ne modifie en rien le contenu.

Vous pouvez stocker des valeurs de données dans des tables et utiliser un curseur comme pointeur vers un jeu de résultats et les informations de traitement connexes.

Voir aussi : Informations de référence sur le langage PL/SQL pour Oracle Database pour plus d'informations sur les enregistrements

À 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 sont utiles pour conserver les données des lignes de table ou de certaines colonnes de lignes de table.

Un enregistrement est une variable composite PL/SQL qui peut stocker des valeurs de données de différents types, similaires à 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, vous utilisez la notation par points : record_name.field_name.

Vous pouvez traiter des champs d'enregistrement comme des variables scalaires. Vous pouvez également transmettre des enregistrements entiers en tant que paramètres de sous-programme.

Les enregistrements sont utiles pour conserver les données des lignes de table ou de certaines colonnes de lignes de table. Chaque champ d'enregistrement correspond à une colonne de table.

Il existe trois façons de créer un enregistrement :

Voir aussi :

Tutoriel : Déclaration d'un type RECORD

Les étapes suivantes montrent comment utiliser l'outil Edit de SQL Developer pour déclarer un type RECORD, sal_info, dont les champs peuvent contenir des informations sur le salaire d'un employé (ID emploi, salaire minimum et maximum pour cet ID emploi, salaire courant et augmentation suggérée).

Etapes pour déclarer RECORD type sal_info :

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

    Sous l'icône hr_conn, une liste des types d'objet de schéma s'affiche.

  2. Développez Ensembles.

    Une liste de packages s'affiche.

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

    Une liste de choix s'affiche.

  4. Sélectionnez Modifier.

    Le volet EMP_EVAL s'ouvre et affiche l'énoncé CREATE PACKAGE qui a créé le paquetage :

    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 volet EMP_EVAL, immédiatement avant END EMP_EVAL, ajoutez ce code :

     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 volet est en italique, ce qui indique que les modifications n'ont pas été enregistrées dans 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 volet EMP_EVAL n'est plus en italique.

    Vous pouvez désormais déclarer des enregistrements de type sal_info, comme dans "Tutoriel : Création et appel d'un sous-programme avec un paramètre d'enregistrement".

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

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

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

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

Comme EVAL_FREQUENCY appellera SALARY_SCHEDULE, la déclaration de SALARY_SCHEDULE doit précéder la déclaration de EVAL_FREQUENCY (sinon, le paquet ne sera pas compilé). Toutefois, la définition de SALARY_SCHEDULE peut se trouver n'importe où dans le corps de l'ensemble.

Étapes 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 Ensembles.

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

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

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

    Le volet EMP_EVAL Body apparaît et affiche le code du corps du package.

  6. Dans le volet Corps EMP_EVAL, immédiatement avant END EMP_EVAL, ajoutez la définition 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 volet est en italique, ce qui indique que les modifications n'ont pas été enregistrées dans la base de données.

  7. Dans le volet EMP_EVAL Body, entrez la fonction eval_frequency et les procédures salary_schedule et add_eval dans 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 effectuant les modifications suivantes :

     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.

À 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ée curseur, vous permet d'extraire le jeu de résultats une rangée à la fois. Les attributs de curseur retournent des informations sur l'état du curseur.

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

Le langage PL/SQL permet également de déclarer des curseurs. Un curseur déclaré a un nom et est associé à une interrogation (énoncé SQL SELECT), généralement une interrogation qui retourne plusieurs rangées. Après avoir déclaré un curseur, vous devez le traiter, implicitement ou explicitement. Pour traiter implicitement le curseur, utilisez un curseur FOR LOOP. La syntaxe est :

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 du jeu de résultats une à la fois ou en masse (avec l'instruction FETCH), puis fermez le curseur (avec l'instruction CLOSE). Après avoir fermé le curseur, vous ne pouvez ni extraire d'enregistrements du jeu de résultats ni voir les valeurs d'attribut du curseur.

La syntaxe de la valeur d'un attribut de curseur implicite est SQL%attribute (par exemple, SQL%FOUND). SQL%attribute fait toujours référence à l'instruction LMD ou SELECT INTO la plus récente.

La syntaxe de la valeur d'un attribut de curseur déclaré est cursor_name%attribute (par exemple, c1%FOUND). Tableau 1 répertorie les attributs de curseur et les valeurs qu'ils peuvent retourner. (Les curseurs implicites ont des attributs supplémentaires qui dépassent la portée de ce manuel.)

Valeurs d'attribut de curseur de la table 1

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

Si le curseur est ouvert (Note de bas de page 1) mais qu'aucune extraction n'a été tentée, NULL.

Si l'extraction la plus récente a retourné une rangée, TRUE.

Si l'extraction la plus récente n'a pas retourné de rangée, FALSE.

Si aucun énoncé LMD ou SELECT INTO n'a été exécuté, NULL.

Si l'énoncé LMD ou SELECT INTO le plus récent a retourné une rangée, TRUE.

Si l'énoncé LMD ou SELECT INTO le plus récent n'a pas retourné de rangée, FALSE.

%PAS TROUVÉ

Si le curseur est ouvert (Note de bas de page 1) mais qu'aucune extraction n'a été tentée, NULL.

Si l'extraction la plus récente a retourné une rangée, FALSE.

Si l'extraction la plus récente n'a pas retourné de rangée, TRUE.

Si aucun énoncé LMD ou SELECT INTO n'a été exécuté, NULL.

Si l'énoncé LMD ou SELECT INTO le plus récent a retourné une rangée, FALSE.

Si l'énoncé LMD ou SELECT INTO le plus récent n'a pas retourné de rangée, TRUE.

%DE NOMBRE DE RANGÉES Si le curseur est ouvert (Note de bas de page 1), un nombre supérieur ou égal à zéro. NULL si aucune instruction LMD 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 FAUX.

Note de bas de page 1 : Si le curseur n'est pas ouvert, l'attribut déclenche l'exception prédéfinie INVALID_CURSOR.

Voir aussi :

Utiliser un curseur déclaré pour extraire les lignes d'un jeu de résultats à la fois

Vous pouvez utiliser un curseur déclaré pour extraire les lignes du jeu de résultats une à la fois.

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

Etapes permettant d'utiliser un curseur déclaré pour extraire des lignes de jeu de résultats une par une :

  1. Dans la partie déclarative :

    1. Déclarez le curseur :

       CURSOR cursor_name IS query;
      

      Pour une syntaxe complète de déclaration de curseur déclaré, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

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

       record_name cursor_name%ROWTYPE;
      

      Pour obtenir la syntaxe %ROWTYPE complète, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

  2. Dans la partie exécutable :

    1. Ouvrez le curseur :

       OPEN cursor_name;
      

      Pour une syntaxe d'énoncé OPEN complète, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

    2. Extrayez des lignes du curseur (lignes du jeu de résultats) une à la fois, à l'aide d'une instruction LOOP dont la syntaxe est similaire au code suivant :

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

      Pour une syntaxe d'énoncé FETCH complète, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

    3. Fermez le curseur :

       CLOSE cursor_name;
      

Pour obtenir la syntaxe complète de l'énoncé CLOSE, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

Tutoriel : Utiliser un curseur déclaré pour extraire les rangées d'un jeu de résultats à la fois

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

Étapes de mise en oeuvre de la procédure EMP_EVAL.EVAL_DEPARTMENT :

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

     PROCEDURE eval_department(dept_id IN employees.department_id%TYPE);
    
  2. Dans le corps du package EMP_EVAL, modifiez la définition de la procédure EVAL_DEPARTMENT comme illustré 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 un exemple étape par étape de modification du corps d'un package, voir "Tutoriel : Déclaration de variables et de constantes dans un sous-programme".)

  3. Compilez la spécification de l'ensemble EMP_EVAL.

  4. Compilez le corps du package EMP_EVAL.

À propos des variables de curseur

Une variable de curseur est comme un curseur qui ne se limite pas à une interrogation. Vous pouvez ouvrir une variable de curseur pour une interrogation, traiter le jeu de résultats, puis utiliser la variable de curseur pour une autre interrogation. Les variables de curseur sont utiles pour transmettre les résultats des interrogations entre les sous-programmes.

Pour plus d'informations sur les curseurs, voir "À propos des curseurs".

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

Un type REF CURSOR fort indique un type de retour, qui est le type RECORD de ses variables de curseur. Le compilateur PL/SQL ne vous permet pas d'utiliser ces variables de curseur fortement tapées pour les interrogations qui retournent des rangées qui ne sont pas du type retour. Les types REF CURSOR forts sont moins sujets aux erreurs que les faibles, mais les faibles sont plus flexibles.

Un type REF CURSOR faible ne spécifie pas de type de retour. Le compilateur PL/SQL accepte les variables de curseur faiblement tapées dans toutes les interrogations. Les types REF CURSOR faibles sont interchangeables. Par conséquent, 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 interrogation spécifique (avec l'instruction OPEN FOR), extraire les lignes une à la fois du jeu de résultats (avec l'instruction FETCH), puis fermer le curseur (avec l'instruction CLOSE) ou l'ouvrir pour une autre interrogation spécifique (avec l'instruction OPEN FOR). L'ouverture de la variable de curseur pour une autre interrogation la ferme pour l'interrogation précédente. Après avoir fermé une variable de curseur pour une interrogation spécifique, vous ne pouvez ni extraire d'enregistrements du jeu de résultats de cette interrogation, ni voir les valeurs d'attribut de curseur pour cette interrogation.

Voir aussi :

Utiliser une variable de curseur pour extraire les lignes d'un jeu de résultats à la fois

Vous pouvez utiliser une variable de curseur pour extraire des lignes de jeu de résultats une à la fois.

La procédure suivante utilise chacune des instructions nécessaires dans sa forme la plus simple, mais fournit des références à leur syntaxe complète.

Etapes permettant d'utiliser une variable de curseur pour extraire les lignes d'un jeu de résultats à la fois :

  1. Dans la partie déclarative :

    1. Déclarez le type REF CURSOR :

       TYPE cursor_type IS REF CURSOR [ RETURN return_type ];
      

      Pour une syntaxe complète de déclaration de type REF CURSOR, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

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

       cursor_variable cursor_type;
      

      Pour obtenir la syntaxe complète de déclaration de variable de curseur, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

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

       record_name return_type;
      

      Pour des informations complètes sur la syntaxe d'une déclaration d'enregistrement, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

  2. Dans la partie exécutable :

    1. Ouvrez la variable de curseur pour une interrogation spécifique :

       OPEN cursor_variable FOR query;
      

      Pour des informations complètes sur la syntaxe de l'énoncé OPEN FOR, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

    2. Extraire des lignes de la variable de curseur (lignes du jeu de résultats) une à la fois, à l'aide d'une instruction LOOP dont la syntaxe est similaire à celle-ci :

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

      Pour des informations complètes sur la syntaxe d'énoncé FETCH, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

    3. Fermez la variable de curseur :

       CLOSE cursor_variable;
      

      Vous pouvez également ouvrir la variable de curseur pour une autre interrogation, qui la ferme pour l'interrogation courante.

      Pour des informations complètes sur la syntaxe de l'énoncé CLOSE, voir Informations de référence sur le langage PL/SQL pour Oracle Database.

Tutoriel : Utiliser une variable de curseur pour extraire les rangées d'un jeu de résultats à 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é (ce qui lui permet de traiter plusieurs services) et comment rendre EMP_EVAL.EVAL_DEPARTMENT et EMP_EVAL.ADD_EVAL plus efficaces.

Comment ce tutoriel rend EMP_EVAL.EVAL_DEPARTMENT et EMP_EVAL.ADD_EVAL plus efficaces : Au lieu de transmettre un champ d'une table à ADD_EVAL et de demander à ADD_EVAL d'utiliser trois interrogations pour extraire trois autres champs d'une même table, EVAL_DEPARTMENT transmet la table entière à ADD_EVAL, et ADD_EVAL utilise la notation par points pour accéder aux valeurs des trois autres champs.

Étapes pour modifier la procédure EMP_EVAL.EVAL_DEPARTMENT afin d'utiliser une variable de curseur :

  1. Dans la spécification du package EMP_EVAL, ajoutez la déclaration de procédure et la définition du type REF CURSOR, comme illustré 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 du package EMP_EVAL, ajoutez une déclaration Forward pour la procédure EVAL_LOOP_CONTROL et modifiez la déclaration de la procédure ADD_EVAL, comme indiqué :

     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 un exemple étape par étape de modification du corps d'un package, voir "Tutoriel : Déclaration de variables et de constantes dans un sous-programme".)

  3. Modifiez la procédure EVAL_DEPARTMENT pour extraire trois jeux de résultats distincts en fonction du service et pour appeler la procédure EVAL_LOOP_CONTROL, comme illustré 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 suit :

     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 du jeu 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 un jeu de résultats contenant tous les 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 l'ensemble EMP_EVAL.

  8. Compilez le corps de l'ensemble EMP_EVAL.