Contrôle du flux du programme

Contrairement à SQL, qui exécute les instructions dans l'ordre dans lequel vous les saisissez, PL/SQL comporte des instructions de contrôle qui vous permettent de contrôler le flux du programme.

A propos des instructions de contrôle

Le langage PL/SQL comprend trois catégories d'instructions de contrôle : les instructions de sélection conditionnelle, les instructions de boucle et les instructions de contrôle séquentielles.

Instructions de sélection conditionnelles permettant d'exécuter des instructions distinctes pour des valeurs des données différentes. Les instructions de sélection conditionnelle sont IF et CASE.

Les instructions Boucle vous permettent de répéter les mêmes instructions avec une série de valeur de données différentes. Les instructions de boucle sont FOR LOOP, WHILE LOOP et LOOP de base. L'instruction EXIT transfère Le contrôle à la fin d'une boucle. L'instruction CONTINUE quitte l'itération en cours d'une boucle et transfère l'ensemble du contrôle à l'itération suivante. EXIT et CONTINUE ont une clause WHEN facultative, dans laquelle vous pouvez indiquer une condition.

Les instructions de contrôle séquentielles vous permettent d'accéder à une instruction libellée spécifiée ou de ne rien faire. Les instructions de contrôle séquentielles sont GOTO et NULL.

Voir aussi : Référence du langage PL/SQL d'Oracle Database pour une présentation des instructions de contrôle PL/SQL

Utilisation de l'instruction IF

L'instruction IF exécute ou ignore une séquence d'instructions selon la valeur d'une expression booléenne.

La syntaxe de l'instruction IF est la suivante :

IF boolean_expression THEN statement [, statement ]
[ ELSIF boolean_expression THEN statement [, statement ] ]...
[ ELSE  statement [, statement ] ]
END IF;

Supposons que votre société évalue les employés deux fois par an pendant les 10 premières années d'embauche, puis seulement une fois pas an. Afin de créer une fonction qui renvoie la fréquence d'évaluation d'un employé, Vous pouvez utiliser une instruction IF pour déterminer la valeur de retour de la fonction, comme dans l'Example 5-4.

Ajoutez la fonction EVAL_FREQUENCY au corps du package EMP_EVAL, mais pas à la spécification. Puisqu'elle ne Figure pas dans la spécification, la fonction EVAL_FREQUENCY est locale pour le package (il peut être appelé uniquement par d'autres sous-programmes du package, pas à partir de l'extérieur du package).

A savoir : Lors de l'utilisation d'une variable PL/SQL dans une instruction SQL, comme dans la deuxième instruction SELECT de l'Exemple 5-4, qualifiez la variable avec le nom du sous-programme pour vous assurer qu'elle n'est pas confondue avec une colonne de table.

Voir aussi :

Exemple 5-4 Instruction IF qui détermine la valeur renvoyée par la fonction

FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
  RETURN PLS_INTEGER
AS
  h_date     EMPLOYEES.HIRE_DATE%TYPE;
  today      EMPLOYEES.HIRE_DATE%TYPE;
  eval_freq  PLS_INTEGER;
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;
  ELSE
    eval_freq := 2;
  END IF;

  RETURN eval_freq;
END eval_frequency;

Utilisation de l'instruction CASE

L'instruction CASE effectue un choix dans une séquence de conditions et exécute l'instruction correspondante.

L'instruction simple CASE évalue une seule expression etla compare à plusieurs valeurs potentielles. Elle présente la syntaxe suivante :

CASE expression
WHEN value THEN statement
[ WHEN value THEN statement ]...
[ ELSE statement [, statement ]... ]
END CASE;

L'instruction recherchée CASE évalue plusieurs expressions booléennes et choisit la première dont La valeur est TRUE. Pour plus d'informations sur l'instruction CASE recherchée, reportez-vous à Oracle Database PL/SQL Language Reference.

Conseil : si vous avez le choix entre un instruction CASE ou des instructions IF imbriquées, utilisez une instruction CASE, qui est à la fois plus lisible et plus efficace.

Supposons que si un employé est évalué une fois dans l'année, la fonction EVAL_FREQUENCY suggère une augmentation du salaire qui dépend de l'identificateur JOB_ID.

Modifiez la fonction EVAL_FREQUENCY comme indiqué dans l'Example 5-5. (Pour plus d'informations sur la procédure d'impression des chaînes, reportez-vous au manuel DBMS_OUTPUT.PUT_LINE Oracle Database PL/SQL Packages and Types Reference.)

Exemple 5-5 Instruction CASE déterminant la chaîne à imprimer

FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
  RETURN PLS_INTEGER
AS
  h_date     EMPLOYEES.HIRE_DATE%TYPE;
  today      EMPLOYEES.HIRE_DATE%TYPE;
  eval_freq  PLS_INTEGER;
  j_id       EMPLOYEES.JOB_ID%TYPE;

BEGIN
  SELECT SYSDATE INTO today FROM DUAL;

  SELECT HIRE_DATE, JOB_ID INTO h_date, j_id
  FROM EMPLOYEES
  WHERE EMPLOYEE_ID = eval_frequency.emp_id;

  IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
    eval_freq := 1;

    CASE j_id
       WHEN 'PU_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 8% salary increase for employee # ' || emp_id);
       WHEN 'SH_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 7% salary increase for employee # ' || emp_id);
       WHEN 'ST_CLERK' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 6% salary increase for employee # ' || emp_id);
       WHEN 'HR_REP' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 5% salary increase for employee # ' || emp_id);
       WHEN 'PR_REP' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 5% salary increase for employee # ' || emp_id);
       WHEN 'MK_REP' THEN DBMS_OUTPUT.PUT_LINE(
         'Consider 4% salary increase for employee # ' || emp_id);
       ELSE DBMS_OUTPUT.PUT_LINE(
         'Nothing to do for employee #' || emp_id);
    END CASE;
  ELSE
    eval_freq := 2;
  END IF;

  RETURN eval_freq;
END eval_frequency;

Voir aussi :

Utilisation de l'instruction FOR LOOP

L'instruction FOR LOOP répète une séquence d'instructions une fois pour chaque entier de la plage lower_bound à Upper_bound.

La syntaxe de FOR LOOP est la suivante :

FOR counter IN lower_bound..upper_bound LOOP
  statement [, statement ]...
END LOOP;

Les instructions entre LOOP et END LOOP peuvent utiliser un compteur, mais ne peuvent pas modifier sa valeur.

Supposons qu'au lieu de suggérer une augmentation du salaire, la fonction EVAL_FREQUENCY rapportera le montant obtenu par le salaire s'il était augmenté chaque année de la valeur proposée, pendant cinq ans.

Modifiez la fonction EVAL_FREQUENCY comme indiqué dans l'Example 5-6. (Pour plus d'informations sur la procédure d'impression des chaînes, reportez-vous à DBMS_OUTPUT.PUT_LINE, Oracle Database PL/SQL Packages and Types Reference.)

Exemple 5-6 - Instruction FOR LOOP calculant le salaire après cinq ans

FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
  RETURN PLS_INTEGER
AS
  h_date      EMPLOYEES.HIRE_DATE%TYPE;
  today       EMPLOYEES.HIRE_DATE%TYPE;
  eval_freq   PLS_INTEGER;
  j_id        EMPLOYEES.JOB_ID%TYPE;
  sal         EMPLOYEES.SALARY%TYPE;
  sal_raise   NUMBER(3,3) := 0;

BEGIN
  SELECT SYSDATE INTO today FROM DUAL;

  SELECT HIRE_DATE, JOB_ID, SALARY INTO h_date, j_id, sal
  FROM EMPLOYEES
  WHERE EMPLOYEE_ID = eval_frequency.emp_id;

  IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
    eval_freq := 1;

    CASE j_id
      WHEN 'PU_CLERK' THEN sal_raise := 
0.08;
      WHEN 'SH_CLERK' THEN sal_raise := 0.07;
      WHEN 'ST_CLERK' THEN sal_raise := 0.06;
      WHEN 'HR_REP'   THEN sal_raise := 0.05;
      WHEN 'PR_REP'   THEN sal_raise := 0.05;
      WHEN 'MK_REP'   THEN sal_raise := 0.04;
      ELSE NULL;
    END CASE;

    IF (sal_raise != 0) THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE('If salary ' || sal || ' increases by ' ||
          ROUND((sal_raise * 100),0) ||
          '% each year for 5 years, it will be:');

        FOR i IN 1..5 LOOP
          sal := sal * (1 + sal_raise);
          DBMS_OUTPUT.PUT_LINE(ROUND(sal, 2) || ' after ' || i || ' year(s)');
        END LOOP;
      END;
    END IF;

  ELSE
    eval_freq := 2;
  END IF;

  RETURN eval_freq;
END eval_frequency;

Voir aussi :

Utilisation de l'instruction WHILE LOOP

L'instruction WHILE LOOP répète une séquence d'instructions tant qu'une condition a la valeur TRUE.

La syntaxe de l'instruction WHILE LOOP est la suivante :

WHILE condition LOOP
  statement [, statement ]...
END LOOP;

Remarque : si les instructions comprises entre LOOP et END LOOP ne permettent jamais à la condition de prendre la valeur FALSE, l'instruction WHILE LOOP est exécutée indéfiniment.

Supposons que la fonction EVAL_FREQUENCY utilise l'instruction WHILE LOOP au lieu de l'instruction FOR LOOP et se termine après que le salaire proposé ait atteint le salaire maximal correspondant à l'identificateur JOB_ID.

Modifiez la fonction EVAL_FREQUENCY comme indiqué dans l'Example 5-7. (Pour plus d'informations sur la procédure d'impression des chaînes, reportez-vous au manuel DBMS_OUTPUT.PUT_LINE Oracle Database PL/SQL Packages and Types Reference.)

Exemple 5-7 Instruction WHILE LOOP qui calcule le salaire jusqu'à la valeur maximale

FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
  RETURN PLS_INTEGER
AS
  h_date      EMPLOYEES.HIRE_DATE%TYPE;
  today       EMPLOYEES.HIRE_DATE%TYPE;
  eval_freq   PLS_INTEGER;
  j_id        EMPLOYEES.JOB_ID%TYPE;
  sal         EMPLOYEES.SALARY%TYPE;
  sal_raise   NUMBER(3,3) := 0;
  sal_max     JOBS.MAX_SALARY%TYPE;

BEGIN
  SELECT SYSDATE INTO today FROM DUAL;

  SELECT HIRE_DATE, j.JOB_ID, SALARY, MAX_SALARY INTO h_date, j_id, sal, sal_max
  FROM EMPLOYEES e, JOBS j
  WHERE EMPLOYEE_ID = eval_frequency.emp_id AND JOB_ID = eval_frequency.j_id;

  IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
    eval_freq := 1;

    CASE j_id
      WHEN 'PU_CLERK' THEN sal_raise := 0.08;
      WHEN 'SH_CLERK' THEN sal_raise := 0.07;
      WHEN 'ST_CLERK' THEN sal_raise := 0.06;
      WHEN 'HR_REP'   THEN sal_raise := 0.05;
      WHEN 'PR_REP'   THEN sal_raise := 0.05;
      WHEN 'MK_REP'   THEN sal_raise := 0.04;
      ELSE NULL;
    END CASE;

    IF (sal_raise != 0) THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE('If salary ' || sal || ' increases by ' ||
          ROUND((sal_raise * 100),0) ||
          '% each year, it will be:');

        WHILE sal <= sal_max LOOP
          sal := sal * (1 + sal_raise);
          DBMS_OUTPUT.PUT_LINE(ROUND(sal, 2));
        END LOOP;

        DBMS_OUTPUT.PUT_LINE('Maximum salary for this job is ' || sal_max);
      END;
    END IF;
  ELSE
    eval_freq := 2;
  END IF;

  RETURN eval_freq;
END eval_frequency;

Voir aussi :

Utilisation des instructions de base LOOP et EXIT WHEN

L'instruction LOOP de base répète une séquence d'instructions.

La syntaxe de l'instruction LOOP de base est la suivante :

LOOP
  statement [, statement ]...
END LOOP;

Au moins une instruction doit être une instruction EXIT ; sinon, l'instruction LOOP s'exécute indéfiniment.

L'instruction EXIT WHEN (instruction EXIT avec la clause facultative WHEN) termine une boucle lorsqu'une condition prend la valeur TRUE et transfère Le contrôle à la fin de la boucle.

Dans la fonction EVAL_FREQUENCY, dans la dernière itération de l'instruction WHILE LOOP, la dernière valeur calculée dépasse habituellement le salaire maximal.

Remplacez l'instruction WHILE LOOP par une instruction LOOP de base comprenant une instruction EXIT WHEN, comme dans l'Example 5-8.

Exemple 5-8 Utilisation de l'instruction EXIT WHEN

FUNCTION eval_frequency (emp_id IN EMPLOYEES.EMPLOYEE_ID%TYPE)
  RETURN PLS_INTEGER
AS
  h_date      EMPLOYEES.HIRE_DATE%TYPE;
  today       EMPLOYEES.HIRE_DATE%TYPE;
  eval_freq   PLS_INTEGER;
  j_id        EMPLOYEES.JOB_ID%TYPE;
  sal         EMPLOYEES.SALARY%TYPE;
  sal_raise   NUMBER(3,3) := 0;
  sal_max     JOBS.MAX_SALARY%TYPE;

BEGIN
  SELECT SYSDATE INTO today FROM DUAL;

  SELECT HIRE_DATE, j.JOB_ID, SALARY, MAX_SALARY INTO h_date, j_id, sal, sal_max
  FROM EMPLOYEES e, JOBS j
  WHERE EMPLOYEE_ID = eval_frequency.emp_id AND JOB_ID = eval_frequency.j_id;

  IF ((h_date + (INTERVAL '12' MONTH)) < today) THEN
    eval_freq := 1;

    CASE j_id
      WHEN 'PU_CLERK' THEN sal_raise := 0.08;
      WHEN 'SH_CLERK' THEN sal_raise := 0.07;
      WHEN 'ST_CLERK' THEN sal_raise := 0.06;
      WHEN 'HR_REP'   THEN sal_raise := 0.05;
      WHEN 'PR_REP'   THEN sal_raise := 0.05;
      WHEN 'MK_REP'   THEN sal_raise := 0.04;
      ELSE NULL;
    END CASE;

    IF (sal_raise != 0) THEN
      BEGIN
        DBMS_OUTPUT.PUT_LINE('If salary ' || sal || ' increases by ' ||
          ROUND((sal_raise * 100),0) ||
          '% each year, it will be:');

        LOOP
          sal := sal * (1 + sal_raise);
          EXIT WHEN sal > sal_max;
          DBMS_OUTPUT.PUT_LINE(ROUND(sal,2));
        END LOOP;

        DBMS_OUTPUT.PUT_LINE('Maximum salary for this job is ' || sal_max);
      END;
    END IF;
  ELSE
    eval_freq := 2;
  END IF;

  RETURN eval_freq;
END eval_frequency;

Voir aussi :