Controllo del flusso dei programmi
A differenza del linguaggio SQL, che esegue le istruzioni nell'ordine in cui sono state immesse, PL/SQL dispone delle istruzioni del controllo che consentono il controllo del flusso del programma.
Informazioni sulle istruzioni di controllo
PL/SQL dispone di tre categorie di istruzioni di controllo: istruzioni di selezione condizionale, istruzioni loop e istruzioni di controllo sequenziali.
Le istruzioni di selezione condizionali consentono di eseguire istruzioni diverse per valori di dati diversi. Le istruzioni di selezione condizionale sono IF e CASE.
Le istruzioni LOOP consentono che si ripetano le stesse istruzioni con una serie di valori dei dati differenti. Le istruzioni LOOP sono FOR LOOP, WHILE LOOP e l'istruzione LOOP di base. L'istruzione EXIT trasferisce il controllo alla fine di un loop. L'istruzione CONTINUE permette di uscire dall'iterazione corrente di un loop e trasferisce il controllo all'iterazione successiva. Sia EXIT che CONTINUE hanno una clausola opzionale WHEN, in cui è possibile specificare una condizione.
Le istruzioni di controllo sequenziali consentono di passare a un'istruzione con etichetta specifica o di non eseguire nulla. Le istruzioni di controllo sequenziali sono GOTO e NULL.
Per una panoramica delle istruzioni di controllo PL/SQL, vedere anche: Oracle Database PL/SQL Language Reference
Uso dell'istruzione IF
L'istruzione IF esegue o salta una sequenza di istruzioni, in base al valore di un'espressione booleana.
L'istruzione IF ha la seguente sintassi:
IF boolean_expression THEN statement [, statement ]
[ ELSIF boolean_expression THEN statement [, statement ] ]...
[ ELSE statement [, statement ] ]
END IF;
Si supponga che la propria azienda valuti i dipendenti due volte all'anno nei primi 10 anni di impiego, ma solo una volta l'anno successivamente. Si desidera una funzione che restituisca la frequenza di valutazione per un dipendente. È possibile utilizzare un'istruzione IF per determinare il valore restituito della funzione, come nell'Esempio 5-4.
Aggiungere la funzione EVAL_FREQUENCY al corpo del package EMP_EVAL, ma non alla specifica. Poiché non si trova nella specifica, la funzione EVAL_FREQUENCY è locale rispetto al package, pertanto può essere richiamata solo da altri sottoprogrammi nel package, non dall'esterno di quest'ultimo.
Suggerimento: quando si utilizza una variabile PL/SQL in un'istruzione SQL, come nella seconda istruzione SELECT in Esempio 5-4, qualificare la variabile con il nome del sottoprogramma per assicurarsi che non venga scambiata per una colonna di tabella.
Vedere anche:
-
Oracle Database PL/SQL Language Reference per la sintassi dell'istruzione IF
-
Oracle Database PL/SQL Language Reference per ulteriori informazioni sull'uso dell'istruzione IF
Istruzione IF di esempio 5-4 che determina il valore restituito della funzione
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 dell'istruzione CASE
L'istruzione CASE sceglie da una sequenza di condizioni ed esegue l'istruzione corrispondente.
L'istruzione CASE semplice valuta una singola espressione e la confronta con diversi valori potenziali. La sintassi è la seguente:
CASE expression
WHEN value THEN statement
[ WHEN value THEN statement ]...
[ ELSE statement [, statement ]... ]
END CASE;
L'istruzione CASE ricercata valuta più espressioni booleane e sceglie la prima parola il cui valore corrisponde a TRUE. Per informazioni sull'istruzione CASE ricercata, vedere Oracle Database PL/SQL Language Reference.
Suggerimento: quando si può utilizzare un'istruzione CASE o istruzioni IF nidificate, utilizzare un'istruzione CASE, in quanto più leggibile e anche al contempo più efficace.
Si supponga che, se un dipendente viene valutato solo una volta l'anno, la funzione EVAL_FREQUENCY suggerisca un aumento di stipendio, che dipende da JOB_ID.
Modificare la funzione EVAL_FREQUENCY come illustrato nell'Esempio 5-5. Per informazioni sulle procedure per la stampa delle stringhe, DBMS_OUTPUT.PUT_LINE, vedere Oracle Database PL/SQL Packages and Types Reference.
Istruzione CASE di esempio 5-5 che determina la stringa da stampare
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;
Vedere anche:
-
Oracle Database PL/SQL Language Reference per la sintassi dell'istruzione CASE
-
Oracle Database PL/SQL Language Reference per ulteriori informazioni sull'uso dell'istruzione CASE
Uso dell'istruzione FOR LOOP
L'istruzione FOR LOOP ripete una sequenza di istruzioni una volta per ogni numero intero nell'intervallo tra lower_bound e upper_bound.
La sintassi di FOR LOOP è:
FOR counter IN lower_bound..upper_bound LOOP
statement [, statement ]...
END LOOP;
Le istruzioni tra LOOP e END LOOP possono utilizzare un contatore, ma non può modificarne il valore.
Supponiamo che, invece di suggerire solo un aumento di stipendio, si supponga che la funzione EVAL_FREQUENCY indichi a quanto corrisponderà lo stipendio se aumentato dell'importo suggerito ogni anno per cinque anni.
Modificare la funzione EVAL_FREQUENCY come illustrato nell'Esempio 5-6. Per informazioni sulla procedura per la stampa delle stringhe, DBMS_OUTPUT.PUT_LINE, vedere Oracle Database PL/SQL Packages and Types Reference.
Esempio 5-6 FOR LOOP Statement che calcola lo stipendio dopo cinque anni
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;
Vedere anche:
-
Oracle Database PL/SQL Language Reference per la sintassi dell'istruzione FOR LOOP
-
Oracle Database PL/SQL Language Reference per ulteriori informazioni sull'uso dell'istruzione FOR LOOP
Uso dell'istruzione WHILE LOOP
L'istruzione WHILE LOOP ripete una sequenza di istruzioni mentre una condizione è TRUE.
La sintassi dell'istruzione WHILE LOOP è:
WHILE condition LOOP
statement [, statement ]...
END LOOP;
Nota: se le istruzioni tra LOOP e END LOOP non fanno mai accadere che la condizione diventi FALSE, l'istruzione WHILE LOOP viene eseguita continuamente.
Si supponga che la funzione EVAL_FREQUENCY utilizzi l'istruzione WHILE LOOP al posto dell'istruzione FOR LOOP e termini prima che lo stipendio proposto superi lo stipendio massimo per JOB_ID.
Modificare la funzione EVAL_FREQUENCY come illustrato nell'Esempio 5-7. Per informazioni sulle procedure per la stampa delle stringhe, DBMS_OUTPUT.PUT_LINE, vedere Oracle Database PL/SQL Packages and Types Reference.
Esempio 5-7 istruzione WHILE LOOP che calcola lo stipendio al massimo
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;
Vedere anche:
-
Oracle Database PL/SQL Language Reference per la sintassi dell'istruzione WHILE LOOP
-
Oracle Database PL/SQL Language Reference per ulteriori informazioni sull'uso dell'istruzione WHILE LOOP
Uso delle istruzioni EXIT WHEN e LOOP di base
L'istruzione LOOP di base ripete una sequenza di istruzioni.
La sintassi dell'istruzione LOOP di base è:
LOOP
statement [, statement ]...
END LOOP;
Almeno un'istruzione deve essere un'istruzione EXIT; in caso contrario, l'istruzione LOOP viene eseguita all'infinito.
L'istruzione EXIT WHEN (l'istruzione EXIT con la clausola opzionale WHEN) consente di chiudere da un loop quando una condizione è TRUE e trasferisce il controllo alla fine del loop.
Nella funzione EVAL_FREQUENCY, nell'ultima iterazione dell'istruzione WHILE LOOP, l'ultimo valore calcolato, in genere, supera lo stipendio massimo.
Modificare l'istruzione WHILE LOOP in un'istruzione LOOP di base che includa l'istruzione EXIT WHEN, come descritto nell'Esempio 5-8.
Esempio 5-8 Uso dell'istruzione 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;
Vedere anche:
-
Oracle Database PL/SQL Language Reference per la sintassi dell'istruzione LOOP
-
Oracle Database PL/SQL Language Reference per la sintassi dell'istruzione EXIT
-
Oracle Database PL/SQL Language Reference per ulteriori informazioni sull'uso delle istruzioni LOOP ed EXIT