控制程序流
与以输入顺序运行语句的 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;
假设您的公司在前 10 年的雇佣期中每年进行两次员工评估,但其后每年只进行一次员工评估。您想通过一个函数返回某个员工的评估频率。这时可以使用 IF 语句来确定函数的返回值,如 Example 5-4 中所示。
请将此 EVAL_FREQUENCY 函数添加到 EMP_EVAL 程序包的主体,而不要添加到其规范中。由于它不在规范中,因此 EVAL_FREQUENCY 是该程序包的本地程序,它只能由程序包中的其他子程序调用,而不能从程序包外部进行调用。
提示:在 SQL 语句中使用 PL/SQL 变量时,如 Example 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 函数,如 Example 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 Language Reference(了解有关 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 函数,如 Example 5-6 中所示。(有关字符串的输出过程 DBMS_OUTPUT.PUT_LINE 的信息,请参阅 Oracle Database PL/SQL Packages and Types Reference。)
用于计算五年后的薪金的 FOR LOOP 语句示例 5-6
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 函数,如 Example 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 Language Reference(了解有关使用 WHILE LOOP 语句的详细信息)
使用基本 LOOP 和 EXIT WHEN 语句
基本 LOOP 语句用于重复执行一个语句序列。
基本 LOOP 语句的语法为:
LOOP
statement [, statement ]...
END LOOP;
至少一个语句必须是 EXIT 语句;否则,LOOP 语句将无限期运行。
EXIT WHEN 语句(带有可选 WHEN 子句的 EXIT 语句)将在条件为 TRUE 时退出循环,并将控制权转至循环结束。
在 EVAL_FREQUENCY 函数中,WHILE LOOP 语句的最后一次迭代所计算得到的值通常会超过最高薪水。
将 WHILE LOOP 语句更改为包含一个 EXIT WHEN 语句的基本 LOOP 语句,如下例所示 Example 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 语句的详细信息)