Control de Flujo de Programa
A diferencia de SQL, que ejecuta sentencias en la orden en la que las introduce, PL/SQL tiene sentencias del control que le permiten controlar el flujo de su programa.
Acerca de las Sentencias de Control
PL/SQL tiene tres categorías de sentencias de control: sentencias de selección condicional, sentencias de bucle y sentencias de control secuenciales.
Las sentencias de selección condicionales le permiten ejecutar diferentes sentencias para distintos valores datos. Las sentencias de selección condicional son IF y CASE.
Las sentencias LOOP le permiten repetir las mismas sentencias con una serie de valores diferentes de datos. Las sentencias LOOP son las sentencias FOR LOOP, WHILE LOOP y LOOP básica. La sentencia EXIT transfiere el control al final de un bucle. La sentencia CONTINUE sale de la iteración actual de un bucle y transfiere el control a la siguiente iteración. Tanto EXIT como CONTINUE tienen una cláusula opcional WHEN en la que puede especificar una condición.
Las sentencias de control secuenciales le permiten ir a una sentencia con etiqueta especificada o no realizar ninguna acción. Las sentencias de control secuenciales son GOTO y NULL.
Consulte también: Referencia de lenguaje PL/SQL de Oracle Database para obtener una visión general de las sentencias de control PL/SQL
Uso de la Sentencia IF
La sentencia IF ejecuta o salta una secuencia de sentencias, dependiendo del valor de una expresión booleana.
La sentencia IF tiene la siguiente sintaxis:
IF boolean_expression THEN statement [, statement ]
[ ELSIF boolean_expression THEN statement [, statement ] ]...
[ ELSE statement [, statement ] ]
END IF;
Supongamos que su compañía evalúa a los empleados dos veces al año en los primeros 10 años de empleo, pero transcurrido ese tiempo, sólo lo hace una vez al año. Desea tener una función que devuelva la frecuencia de evaluación de un empleado. Puede utilizar una sentencia IF para determinar el valor de retorno de la función, como en el Example 5-4.
Agregue la función EVAL_FREQUENCY al cuerpo del paquete EMP_EVAL, pero no a la especificación. Debido al hecho de que no está en la especificación, EVAL_FREQUENCY es local para el paquete, y sólo puede ser invocado por otros subprogramas en el paquete, no desde fuera del paquete.
Consejo: al utilizar una variable PL/SQL en una sentencia SQL, como en la segunda sentencia SELECT del Ejemplo 5-4, cualifique la variable con el nombre del subprograma para asegurarse de que no se confunda con una columna de tabla.
Consulte además:
-
Referencia de lenguaje PL/SQL de Oracle Database para la sintaxis de la sentencia IF
-
Referencia de lenguaje PL/SQL de Oracle Database para obtener más información sobre el uso de la sentencia IF
Ejemplo 5-4 Sentencia IF que determina el valor de retorno de la función
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;
Uso de la Sentencia CASE
La sentencia CASE elige entre una secuencia de condiciones y ejecuta la sentencia correspondiente.
La sentencia CASE simple evalúa una sola expresión y la compara con varios valores potenciales. Tiene la siguiente sintaxis:
CASE expression
WHEN value THEN statement
[ WHEN value THEN statement ]...
[ ELSE statement [, statement ]... ]
END CASE;
La sentencia CASE buscada evalúa varias expresiones booleanas y elige la primera cuyo valor sea TRUE. Para obtener información sobre la sentencia CASE buscada, consulte Referencia de lenguaje PL/SQL de Oracle Database.
Consejo: cuando pueda utilizar tanto una sentencia CASE como una sentencia IF anidada, utilice la sentencia CASE, puesto que es más legible y más eficaz.
Supongamos que, si a un empleado se lo evalúa sólo una vezal año, desee que la función EVAL_FREQUENCY sugiera un aumento de salario, lo cual depende de JOB_ID.
Cambie la función EVAL_FREQUENCY como se muestra en el Example 5-5. (Para obtener información sobre los procedimientos que imprimen las cadenas, DBMS_OUTPUT.PUT_LINE, consulte Oracle Database PL/SQL Packages and Types Reference).
Ejemplo 5-5 Sentencia CASE que Determina qué Cadena se Debe Imprimir
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;
Consulte además:
-
Referencia de lenguaje PL/SQL de Oracle Database para la sintaxis de la sentencia CASE
-
Referencia de lenguaje PL/SQL de Oracle Database para obtener más información sobre el uso de la sentencia CASE
Uso de la Sentencia FOR LOOP
La sentencia FOR LOOP repite una secuencia de sentencias una vez para cada entero del rango entre lower_bound y upper_bound.
La sintaxis de FOR LOOP es:
FOR counter IN lower_bound..upper_bound LOOP
statement [, statement ]...
END LOOP;
Las sentencias entre LOOP y END LOOP pueden utilizar contador, pero no pueden cambiar su valor.
Supongamos que, en lugar de sólo sugerir un incremento de salario, desea que la función EVAL_FREQUENCY informe sobre cuánto sería el salario si éste aumentara en la cantidad sugerida cada año Durante cinco años.
Cambie la función EVAL_FREQUENCY como se muestra en el Example 5-6. (Para obtener información sobre el procedimiento que imprime las cadenas, DBMS_OUTPUT.PUT_LINE, consulte Referencia de tipos y paquetes PL/SQL de Oracle Database).
Ejemplo 5-6 Sentencia FOR LOOP que calcula el salario después de cinco años
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;
Consulte además:
-
Referencia de lenguaje PL/SQL de Oracle Database para la sintaxis de la sentencia FOR LOOP
-
Referencia de lenguaje PL/SQL de Oracle Database para obtener más información sobre el uso de la sentencia FOR LOOP
Uso de la Sentencia WHILE LOOP
La sentencia WHILE LOOP repite una secuencia de sentencias mientras que la condición es TRUE.
La sintaxis de la sentencia WHILE LOOP es:
WHILE condition LOOP
statement [, statement ]...
END LOOP;
Nota: Si las sentencias entre LOOP y END LOOP nunca hacen que la condición se convierta en FALSE, la sentencia WHILE LOOP se ejecuta indefinidamente.
Supongamos que la función EVAL_FREQUENCY utiliza la sentencia WHILE LOOP, en lugar de la sentencia FOR LOOP, y termina una vez, que del salario propuesto exceda el sueldo máximo para JOB_ID.
Cambie la función EVAL_FREQUENCY como se muestra en el Example 5-7. (Para obtener información sobre los procedimientos que imprimen las cadenas, DBMS_OUTPUT.PUT_LINE, consulte Oracle Database PL/SQL Packages and Types Reference).
Ejemplo 5-7 Sentencia WHILE LOOP que Calcula el Sueldo al Máximo
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;
Consulte además:
-
Referencia de lenguaje PL/SQL de Oracle Database para la sintaxis de la sentencia WHILE LOOP
-
Referencia de lenguaje PL/SQL de Oracle Database para obtener más información sobre el uso de la sentencia WHILE LOOP
Uso de Sentencias Básicas LOOP y EXIT WHEN
La sentencia LOOP básica repite una secuencia de sentencias.
La sintaxis de la sentencia LOOP básica es:
LOOP
statement [, statement ]...
END LOOP;
Al menos una sentencia debe ser una sentencia EXIT; de lo contrario, la sentencia LOOP se ejecuta indefinidamente.
La sentencia EXIT WHEN (la sentencia EXIT con su cláusula opcional WHEN) sale de un bucle cuando una condición es TRUE y transfiere el control al final del bucle.
En la función EVAL_FREQUENCY, en la última iteración de la sentencia WHILE LOOP, el último valor calculado suele exceder al salario máximo.
Cambie la sentencia WHILE LOOP a una sentencia LOOP básica que incluye una sentencia EXIT WHEN, como se muestra en el Example 5-8.
Ejemplo 5-8 Uso de la Sentencia 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;
Consulte además:
-
Referencia de lenguaje PL/SQL de Oracle Database para la sintaxis de la sentencia LOOP
-
Referencia de lenguaje PL/SQL de Oracle Database para la sintaxis de la sentencia EXIT
-
Referencia de lenguaje PL/SQL de Oracle Database para obtener más información sobre el uso de las sentencias LOOP y EXIT