Controlando o Fluxo do Programa
Ao contrário da linguagem SQL, que executa instruções na ordem em que você as insere, a PL/SQL tem instruções de controle que permitem controlar o fluxo do seu programa.
Sobre Instruções de Controle
O código PL/SQL tem três categorias de instruções de controle: instruções de seleção condicional, instruções de loop e instruções de controle sequencial.
As instruções de seleção condicionais permitem executar instruções diferentes para valores diferentes de dados. As instruções de seleção condicional são IF e CASE.
As instruções de loop permitem que você repita as mesmas instruções com uma série de valores diferentes de dados. As instruções de loop são FOR LOOP, WHILE LOOP e LOOP básico. A instrução EXIT transfere o controle para o fim de um loop. A instrução CONTINUE sai da iteração atual de um loop e transfere o controle para a próxima iteração. EXIT e CONTINUE têm uma cláusula WHEN opcional, na qual você pode especificar uma condição.
Instruções de controle sequencial permitem que você vá para uma instrução rotulada especificada ou não faça nada. As instruções de controle sequenciais são GOTO e NULL.
Consulte Também: Referência de Linguagem PL/SQL do Oracle Database para obter uma visão geral das instruções de controle PL/SQL
Usando a Instrução IF
A instrução IF executa ou ignora uma sequência de instruções, dependendo do valor de uma expressão booleana.
A instrução IF tem esta sintaxe:
IF boolean_expression THEN statement [, statement ]
[ ELSIF boolean_expression THEN statement [, statement ] ]...
[ ELSE statement [, statement ] ]
END IF;
Suponha que sua empresa avalie os funcionários duas vezes por ano nos primeiros dez anos de emprego e·apenas uma vez por ano após esse período. Você quer uma função que retorne a frequência de avaliação de um funcionário . Você pode usar uma instrução IF para determinar o valor de retorno da função, conforme o Exemplo 5-4.
Adicione a função EVAL_FREQUENCY ao corpo do pacote EMP_EVAL, mas não à especificação. Como não está na especificação, EVAL_FREQUENCY é local para o pacote - só pode ser chamado por outros subprogramas do pacote, não de fora do pacote.
Dica: ao usar uma variável PL/SQL em uma instrução SQL, como na segunda instrução SELECT no Exemplo 5-4, qualifique a variável com o nome do subprograma para garantir que ela não seja confundida com uma coluna de tabela.
Consulte também:
-
Referência da Linguagem PL/SQL do Oracle Database para a sintaxe da instrução IF
-
Oracle Database PL/SQL Language Reference para saber mais sobre como usar a instrução IF
Exemplo 5-4 Instrução IF que Determina o Valor de Retorno da Função
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;
Usando a Instrução CASE
A instrução CASE escolhe em uma sequência de condições e executa a instrução correspondente.
A instrução CASE simples avalia uma única expressão e a compara com vários valores potenciais. Ela tem esta sintaxe:
CASE expression
WHEN value THEN statement
[ WHEN value THEN statement ]...
[ ELSE statement [, statement ]... ]
END CASE;
A instrução CASE pesquisada avalia várias expressões Boolianas e escolhe a primeira cujo valor é TRUE. Para obter informações sobre a instrução CASE pesquisada, consulte Referência de Linguagem PL/SQL do Oracle Database.
Dica: Quando você pode usar uma instrução CASE ou instruções IF aninhadas, use uma instrução CASE-ele é mais legível e mais eficiente.
Suponhamos que, se um funcionário for avaliado apenas uma vez ao ano, você deseje que a função EVAL_FREQUENCY sugira um aumento salarial, o que depende do JOB_ID.
Altere a função EVAL_FREQUENCY, conforme mostrado no Exemplo 5-5. (Para mais informações sobre os procedimentos que imprimem as strings, DBMS_OUTPUT.PUT_LINE, consulte Referência de Tipos e Pacotes PL/SQL do Oracle Database.)
Exemplo 5-5 Instrução CASE que Determina Qual String 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 também:
-
Referência da Linguagem PL/SQL do Oracle Database para ver a sintaxe da instrução CASE
-
Oracle Database PL/SQL Language Reference para saber mais sobre como usar a instrução CASE
Usando a Instrução FOR LOOP
A instrução FOR LOOP repete uma sequência de instruções uma vez para cada número inteiro na faixa lower_bound até upper_bound.
A sintaxe do FOR LOOP é:
FOR counter IN lower_bound..upper_bound LOOP
statement [, statement ]...
END LOOP;
As instruções entre LOOP e END LOOP podem usar contador, mas não podem alterar seu valor.
Suponha que, em vez de apenas sugerir um aumento salarial, você queira que a função EVAL_FREQUENCY reporte qual seria o salário se ele aumentasse pela quantia sugerida a cada ano por cinco anos.
Altere a função EVAL_FREQUENCY, conforme mostrado no Exemplo 5-6. (Para mais informações sobre o procedimento que imprime as strings, DBMS_OUTPUT.PUT_LINE, consulte Referência de Tipos e Pacotes PL/SQL do Oracle Database.)
Exemplo 5-6 FOR LOOP - Instrução que Calcula Salário Após Cinco Anos
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 também:
-
Referência da Linguagem PL/SQL do Oracle Database para a sintaxe da instrução FOR LOOP
-
Referência de Linguagem PL/SQL do Oracle Database para mais informações sobre como usar a instrução FOR LOOP
Usando a Instrução WHILE LOOP
A instrução WHILE LOOP repete uma sequência de instruções enquanto uma condição é TRUE.
A sintaxe da instrução WHILE LOOP é:
WHILE condition LOOP
statement [, statement ]...
END LOOP;
Observação: Se as instruções entre LOOP e END LOOP nunca fizerem com que a condição se torne FALSA, a instrução WHILE LOOP será executada indefinidamente.
Suponha que a função EVAL_FREQUENCY use a instrução WHILE LOOP em vez da instrução FOR LOOP e termina após o salário proposto exceder o salário máximo para o JOB_ID.
Altere a função EVAL_FREQUENCY, conforme mostrado no Exemplo 5-7. (Para mais informações sobre os procedimentos que imprimem as strings, DBMS_OUTPUT.PUT_LINE, consulte Referência de Tipos e Pacotes PL/SQL do Oracle Database.)
Exemplo 5-7 Instrução WHILE LOOP que Calcula o Salário para o 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 também:
-
Referência da Linguagem PL/SQL do Oracle Database para a sintaxe da instrução WHILE LOOP
-
Oracle Database PL/SQL Language Reference para saber mais sobre como usar a instrução WHILE LOOP
Usando as Instruções LOOP Básico e EXIT WHEN
A instrução LOOP básica repete uma sequência de instruções.
A sintaxe da instrução LOOP básica é:
LOOP
statement [, statement ]...
END LOOP;
Pelo menos uma instrução deve ser EXIT; caso contrário, a instrução LOOP é executada indefinidamente.
A instrução EXIT WHEN (a instrução EXIT com sua cláusula WHEN opcional) sai de um loop quando uma condição é TRUE e transfere controle para o final do loop.
Na função EVAL_FREQUENCY, na última iteração da instrução WHILE LOOP, o último valor calculado geralmente excede o salário máximo.
Altere a instrução WHILE LOOP para uma instrução LOOP básica que inclua uma instrução EXIT WHEN, como no Exemplo 5-8.
Exemplo 5-8 Usando a Instrução 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 também:
-
Referência da Linguagem PL/SQL do Oracle Database para a sintaxe da instrução LOOP
-
Referência da Linguagem PL/SQL do Oracle Database para a sintaxe da instrução EXIT
-
Referência da Linguagem PL/SQL do Oracle Database para saber mais sobre como usar as instruções LOOP e EXIT