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 :
-
Déclarez un type RECORD, puis déclarez une variable de ce type.
Utilisez la syntaxe suivante :
TYPE record_name IS RECORD ( field_name data_type [:= initial_value] [, field_name data_type [:= initial_value ] ]... ); variable_name record_name; -
Déclarez une variable de type table_name%ROWTYPE.
Les champs de la table ont les mêmes noms et types de données que les colonnes de la table.
-
Déclarez une variable de type cursor_name%ROWTYPE.
Les champs de la table ont les mêmes noms et types de données que les colonnes de la table dans la clause FROM de l'instruction SELECT du curseur.
Voir aussi :
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour plus d'informations sur la définition des types RECORD et la déclaration d'enregistrements de ce type
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour la syntaxe d'une définition de type RECORD
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour plus d'informations sur l'attribut %ROWTYPE
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour la syntaxe de l'attribut %ROWTYPE
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 :
-
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.
-
Développez Ensembles.
Une liste de packages s'affiche.
-
Cliquez avec le bouton droit de la souris sur EMP_EVAL.
Une liste de choix s'affiche.
-
Sélectionnez Modifier.
Le volet EMP_EVAL s'ouvre et affiche l'énoncé
CREATE PACKAGEqui 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; -
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.
-
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 :
-
Créez une procédure, SALARY_SCHEDULE, dont le paramètre est de type
sal_info. -
Modifiez la fonction EVAL_FREQUENCY afin qu'elle déclare un enregistrement, emp_sal, de type
sal_info, alimente ses champs et le transmet à la procédure SALARY_SCHEDULE.
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 :
-
Dans le cadre Connexions, développez hr_conn.
-
Dans la liste des types d'objet de schéma, développez Ensembles.
-
Dans la liste des ensembles, développez EMP_EVAL.
-
Dans la liste des choix, cliquez avec le bouton droit de la souris sur EMP_EVAL Body.
-
Dans la liste des choix, sélectionnez Modifier.
Le volet EMP_EVAL Body apparaît et affiche le code du corps du package.
-
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.
-
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 -
Modifiez la fonction
EVAL_FREQUENCYen 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; -
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, Si l'énoncé LMD ou SELECT INTO le plus récent n'a pas retourné de rangée, |
| %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 :
-
"À propos des énoncés LMD (Langage de manipulation de données)"
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour plus d'informations sur l'énoncé SELECT INTO
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour plus d'informations sur la gestion des curseurs dans PL/SQL
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 :
-
Dans la partie déclarative :
-
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.
-
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.
-
-
Dans la partie exécutable :
-
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.
-
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.
-
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 :
-
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); -
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".)
-
Compilez la spécification de l'ensemble EMP_EVAL.
-
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 :
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour plus d'informations sur l'utilisation des variables de curseur
-
Informations de référence sur le langage PL/SQL pour Oracle Database pour la syntaxe de déclaration de variable de curseur
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 :
-
Dans la partie déclarative :
-
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.
-
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.
-
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.
-
-
Dans la partie exécutable :
-
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.
-
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.
-
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 :
-
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; -
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".)
-
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; -
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; -
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; -
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; -
Compilez la spécification de l'ensemble
EMP_EVAL. -
Compilez le corps de l'ensemble
EMP_EVAL.