控制程式流程
與執行陳述式的 SQL 不同,其執行順序為您輸入陳述式,PL/SQL 具有控制陳述式,可讓您控制程式的流程。
關於控制敘述句
PL/SQL 有三種類別的控制敘述句:條件選取敘述句、迴圈敘述句以及循序控制敘述句。
條件式選擇敘述句可讓您針對不同的資料值執行不同的敘述句。條件選取陳述式為 IF 與 CASE。
迴圈敘述句可讓您使用一系列不同的資料值重複相同的敘述句。迴圈敘述句為 FOR LOOP、WHILE LOOP 以及基本的 LOOP。EXIT 敘述句會將控制權傳輸至迴圈的結尾。CONTINUE 敘述句會結束迴圈的目前重複,並將控制轉移到下一個重複。EXIT 和 CONTINUE 都具有選擇性的 WHEN 子句,您可以在此指定條件。
循序控制陳述式可讓您移至指定的有標籤陳述式,或不執行任何動作。循序控制陳述式為 GOTO 與 NULL。
另請參閱:Oracle Database PL/SQL Language Reference,瞭解 PL/SQL 控制敘述句的簡介
使用 IF 敘述句
根據布林表示式的值,IF 陳述式會執行或略過一系列的陳述式。
IF 陳述式具有下列語法:
IF boolean_expression THEN statement [, statement ]
[ ELSIF boolean_expression THEN statement [, statement ] ]...
[ ELSE statement [, statement ] ]
END IF;
假設您的公司在員工任職的第一個十年中,每一年進行兩次員工評估,之後每年評估一次。如需可傳回員工評估頻率的函數,您可以使用 IF 陳述式來決定函數的傳回值,如範例 5-4 中所示。
將 EVAL_FREQUENCY 功能新增至 EMP_EVAL 套裝程式的主體,而非新增至規格。因為它不在規格中,所以 EVAL_FREQUENCY 是套件的本機元件 - 它只能由套件中的其他子程式呼叫,而非從套件外部叫用。
提示:在 SQL 陳述式中使用 PL/SQL 變數時,如同在範例 5-4 中的第二個 SELECT 陳述式中,使用子程式名稱來限定變數,以確保表格資料欄不會發生錯誤。
另請參閱:
-
Oracle Database PL/SQL Language Reference,瞭解 IF 敘述句的語法
-
Oracle Database PL/SQL Language Reference,瞭解有關使用 IF 陳述式的詳細資訊
範例 5-4 決定函數傳回值的 IF 敘述句
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;
使用 CASE 敘述句
CASE 敘述句會從一系列的條件中選擇,並執行對應的敘述句。
簡單的 CASE 陳述式會評估單一表示式,並將其與數個潛在值進行比較。它的語法如下:
CASE expression
WHEN value THEN statement
[ WHEN value THEN statement ]...
[ ELSE statement [, statement ]... ]
END CASE;
搜尋的 CASE 敘述句會評估多個布林表示式,並選擇其值為 TRUE 的第一個表示式。如需搜尋之 CASE 敘述句的相關資訊,請參閱 Oracle Database PL/SQL Language Reference。
提示:當您可以使用 CASE 陳述式或巢狀 IF 陳述式時,請使用 CASE 陳述式,這兩種方式都比較容易閱讀且更有效率。
假設,如果員工每年僅評估一次,您希望 EVAL_FREQUENCY 函數建議加薪,這取決於 JOB_ID。
變更 EVAL_FREQUENCY 函數,如範例 5-5 所示。(如需列印字串 DBMS_OUTPUT.PUT_LINE 的程序相關資訊,請參閱 Oracle Database PL/SQL Packages and Types Reference。)
範例 5-5 決定要列印之字串的 CASE 敘述句
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;
另請參閱:
-
Oracle Database PL/SQL 語言參照,瞭解 CASE 敘述句的語法
-
Oracle Database PL/SQL Language Reference,瞭解有關使用 CASE 敘述句的詳細資訊
使用 FOR LOOP 敘述句
FOR LOOP 陳述式會為範圍 lower_bound 到 upper_bound 的每個整數,重複一連串陳述式。
FOR LOOP 的語法為:
FOR counter IN lower_bound..upper_bound LOOP
statement [, statement ]...
END LOOP;
LOOP 與 END LOOP 之間的陳述式可使用計數器,但無法變更其值。
假設您不要只建議加薪,而是希望 EVAL_FREQUENCY 函數報告薪資在每年建議的金額增加五年後,會增加多少薪資。
變更 EVAL_FREQUENCY 函數,如範例 5-6 所示。(如需列印字串 DBMS_OUTPUT.PUT_LINE 的程序相關資訊,請參閱 Oracle Database PL/SQL Packages and Types Reference。)
範例 5-6 FOR 計算五年後薪資的 LOOP 陳述式
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;
另請參閱:
-
Oracle Database PL/SQL Language Reference,瞭解 FOR LOOP 敘述句的語法
-
Oracle Database PL/SQL Language Reference,瞭解有關使用 FOR LOOP 敘述句的詳細資訊
使用 WHILE LOOP 敘述句
WHILE LOOP 陳述式在條件為 TRUE 時,重複一系列陳述式。
WHILE LOOP 敘述句的語法為:
WHILE condition LOOP
statement [, statement ]...
END LOOP;
注意:如果 LOOP 與 END LOOP 之間的敘述句永遠不會導致條件變成 FALSE,則 WHILE LOOP 敘述句會無限期地執行。
假設 EVAL_FREQUENCY 函數使用 WHILE LOOP 陳述式,而非 FOR LOOP 陳述式,且在提議的薪資超過 JOB_ID 的最高薪資之後結束。
變更 EVAL_FREQUENCY 函數,如範例 5-7 所示。(如需列印字串 DBMS_OUTPUT.PUT_LINE 的程序相關資訊,請參閱 Oracle Database PL/SQL Packages and Types Reference。)
範例 5-7 計算薪資至上限的 WHILE LOOP 陳述式
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;
另請參閱:
-
Oracle Database PL/SQL Language Reference,瞭解 WHILE LOOP 敘述句的語法
-
Oracle Database PL/SQL 語言參照,瞭解有關使用 WHILE LOOP 敘述句的詳細資訊
使用基本 LOOP 和 EXIT WHEN 敘述句
基本的 LOOP 敘述句重複一連串的敘述句。
基本 LOOP 敘述句的語法如下:
LOOP
statement [, statement ]...
END LOOP;
至少一個敘述句必須是 EXIT 敘述句;否則,LOOP 敘述句將無限期執行。
當條件為 TRUE 且將控制權傳輸至迴圈結尾時,EXIT WHEN 敘述句 (EXIT 敘述句及其選擇性的 WHEN 子句) 就會結束迴圈。
在 EVAL_FREQUENCY 函數中,最後一次反覆執行 WHILE LOOP 陳述式時,最後計算的值通常超過最高薪資。
將 WHILE LOOP 敘述句變更成包含 EXIT WHEN 敘述句的基本 LOOP 敘述句,如範例 5-8 。
範例 5-8 使用 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;
另請參閱:
-
Oracle Database PL/SQL Language Reference,瞭解 LOOP 敘述句的語法
-
Oracle Database PL/SQL Language Reference,瞭解 EXIT 敘述句的語法
-
Oracle Database PL/SQL Language Reference,瞭解有關使用 LOOP 和 EXIT 敘述句的詳細資訊