说明:
PL/SQL(Procedural Language/SQL)是一种过程化语言,在PL/SQL 中可以通过IF 语句或LOOP 语句实现控制程序的执行流程,甚至可以定义变量,以便在语句之间传递数据信息,这样PL/SQL语言就能够实现操控程序处理的细节过程,不像普通的SQL语句(如DML语句、DQL语句)那样没有流程控制,也不存在变量,因此使用PL/SQL语言可以实现比较复杂的业务逻辑。PL/SQL是Oracle的专用语言,它是对标准SQL语言的扩展,它允许在其内部嵌套普通的SQL语句,这样就将SQL语句的数据操纵能力、数据查询能力和PL/SQL的过程处理能力结合在一起,到达各自取长补短的目的。
[oracle@MaxwellDBA ~]$ sqlplus / as sysdba
SQL*Plus: Release 19.0.0.0.0 - Production on Mon Mar 13 11:28:10 2023
Version 19.3.0.0.0
Copyright (c) 1982, 2019, Oracle. All rights reserved.
Connected to:
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.3.0.0.0
sys@cdb$root:orclcdb> conn SCOTT/TIGER@ORCLPDB1
Connected.
scott@orclpdb1:orclcdb> show user;
USER is "SCOTT"
scott@orclpdb1:orclcdb> show con_name;
CON_NAME
------------------------------
ORCLPDB1
scott@orclpdb1:orclcdb> set serveroutput on
declare
a int:=100;
3 b int:=200;
4 c number;
begin
c:=(a+b)/(a-b);
7 dbms_output.put_line(c);
8 exception
9 when zero_divide then
10 dbms_output.put_line('除数不许为零!');
end;
12 /
-3
PL/SQL procedure successfully completed.
scott@orclpdb1:orclcdb>
[DECLARE]
--声明部分,可选
BEGIN
--执行部分,必须
[EXCEPTION]
--异常处理部分,可选
END
注释用于对程序代码的解释说明,它能够增强程序的可读性,使程序更易于理解。注释编译时被PL/SQL编译器忽略掉,注释有单行注释和多行注释两种情况。
单行注释由两个连接字符“--”开始,后面紧跟着注释内容。
set serveroutput on -- 服务器段输出结果
declare
Num_sal number; -- 声明一个数值变量
Var_ename varchar2(20); -- 声明一个字符串变量
begin
select ename,sal into Var_ename,Num_sal from emp where empno=7369; --检索指定的值并存储到变量中
dbms_output.put_line(Var_ename||'的工资是'||Num_sal); --输出变量中值
end;
/
多行注释由/*开头,由*/结尾,这个大多数编程语言是相同的。
set serveroutput on /*服务器段输出结果*/
declare
Num_sal number; /*声明一个数值变量*/
Var_ename varchar2(20); /*声明一个字符串变量*/
begin
select ename,sal into Var_ename,Num_sal from emp where empno=7369; /*检索指定的值并存储到变量中*/
dbms_output.put_line(Var_ename||'的工资是'||Num_sal); /*输出变量中值*/
end;
/
为了提高用户的编程效率和解决复杂的业务逻辑需求,PL/SQL 语言除了可以使用Oracle规定的基本数据类型外,还提供了 3 种特殊的数据类型,分别为%TYPE类型、RECORD类型、%ROWTYPE类型。本实例主要讲解了%TYPE类型的变量。
使用%TYPE 关键字可以声明一个与指定列名称相同的数据类型,它通常紧跟在指定列名的后面。
set serveroutput on /*服务器段输出结果*/
declare
var_ename emp.ename%type; /*声明与ename列类型相同*/
var_job emp.job%type; /*声明与job列类型相同的变量*/
begin
select ename,job into var_ename,var_job from emp where empno=7369; /*检索指定的值并存储到变量中*/
dbms_output.put_line(var_ename||'的工作是'||var_job); /*输出变量中值*/
end;
/
%ROWTYPE类型的变量结合了“%TYPE类型”和“记录类型”变量的优点,它可以根据数据表中行的结构定义一种特殊的数据类型,用来存储从数据表中检索到的一行数据。它的语法形式很简单,如下所示:
rowVar_name table_name%rowtype;
● rowVar_name:表示可以存储一行数据的变量名。
● table_name:指定的表名。
set serveroutput on
declare
rowVar_emp emp%rowtype; -- 定义能够存储emp表中的一行数据的变量 rowVar_emp
begin
select * into rowVar_emp from emp where empno=7369; -- 检查数据
/*输出雇员信息*/
dbms_output.put_line('雇员'||rowVar_emp.ename||'的编号是'||rowVar_emp.empno||',职务是'||rowVar_emp.job);
end;
/
单词 RECORD有“记录”之意,因此RECORD类型也称作“记录类型”,使用该类型的变量可以存储由多个列值组成的一行数据。声明一个记录类型emp_type,然后使用该类型的变量存储emp表中的一条记录信息,并输出这条记录信息。
declare
type emp_type is record /*声明record类型emp_type*/
(
var_ename varchar2(20), /*定义字段/成员变量*/
var_job varchar2(20),
var_sal number
);
empinfo emp_type; /*定义变量*/
begin
select ename,job,sal into empinfo
from emp where empno=7369; /*检索数据*/
/*输出雇员信息*/
dbms_output.put_line('雇员'||empinfo.var_ename||'的职务是'||empinfo.var_job||'、工资是'||empinfo.var_sal);
end;
/
1.定义变量
变量是指其值在程序运行过程中可以改变的数据存储结构,定义变量必须的元素就是变量名和数据类型,另外还有可选择的初始值,其标准语法格式如下:
<变量名><数据类型> [(长度):=<初始值>];
可见,与很多面向对象的编程语言不同,PL/SQL 中的变量定义要求变量名在数据类型的前面,而不是后面;语法中的长度和初始值是可选项,需要根据实际情况而定。
2.定义常量
常量是指其值在程序运行过程中不可改变的数据存储结构,定义常量必须的元素包括常量名、数据类型、常量值和constant关键字,其标准语法格式如下:
<常量名> constant <数据类型>:=<常量值>;
对于一些固定的数值,如圆周率、光速等,为了防止不慎被改变,最好定义成变量。
(1)定义一个用于存储国家名称的可变字符串变量var_countryname,该变量的最大长度是50,并且该变量的初始值为“中国”
var_countryname varchar2(50):='中国';
(2)定义一个常量con_day,用来存储一年的天数,代码如下
con_day constant integer:=365;
选择语句也称之为条件语句,它的主要作用是根据条件的变化选择执行不同的代码,本实例用到的是if…then语句。定义两个字符串变量,然后赋值,接着使用if…then语句比较两个字符串变量的长度,并输出比较结果。
if...then语句是选择语句中最简单的一种形式,它只做一种情况或条件判断,其语法格式如下:
if < condition_expression> then
plsql_sentence
end if;
set serveroutput on
declare
var_name1 varchar2(50); -- 定义两个字符串变量
var_name2 varchar2(50);
begin
var_name1:='East'; --给两个字符串变量赋值
var_name2:='xiaoke';
if length(var_name1) < length(var_name2) then --比较两个字符串的长度大小
/*输出比较后的结果*/
dbms_output.put_line('字符串'||var_name1||"的长度比字符串"||"var_name2"||的长度小);
end if;
end;
/
现判断两种情况,只要if后面的条件表达式为false,程序就会执行else语句下面的PL/SQL语句。本实例通过if...then...else语句实现只有年龄大于等于56岁,才可以申请退休,否则程序会提示不可以申请退休。
本实例用到了if...then...else语句,其语法格式如下:
if < condition_expression> then
plsql_sentence1;
else
plsql_sentence2;
end if;
set serveroutput on
declare
age int:= 59;
begin
if age >= 60 then
dbms_output.put_line('您可以申请退休了!');
else
dbms_output.put_line('您的年龄小于60岁,不可以申请退休')
end if;
end;
/
if...then...elsif 语句实现了多分支判断选择,它使程序的判断选择条件更加丰富,更加多样化,该语句中的哪个判断分支的表达式为true,那么程序就会执行其下面对应的PL/SQL语句,其语法格式如下:
if < condition_expression1 > then
plsql_sentence_1;
elsif
< condition_expression2 > then
plsql_sentence_2;
…
else
plsql_sentence_n;
end if;
set serveroutput on
declare
month int:=10; --定义整形变量并赋值
begin
if month >= 0 and month <= 3 then -- 判断春季
dbms_output.put_line('这是春季');
elsif month >=4 and month <=6 then -- 判断夏季
dbms_output.put_line('这是夏季');
elsif month>=7 and month <= 9 then -- 判断秋季
dbms_output.put_line('这是秋季');
elsif month>=10 and month <= 12 then -- 判断冬季
dbms_output.put_line('这是冬季')
else
dbms_output.put_line('对不起,月份不合法!')
end if
end;
/
从Oracle 9i 以后,PL/SQL 也可以像其他编程语言一样使用case 语句,case 语句的执行方式与if...then...elsif语句十分相似。在case关键字的后面有一个选择器,它通常是一个变量,程序就从这个选择器开始执行,接下来是when子句,并且在when关键字的后面是一个表达式,程序将根据选择器的值去匹配每个 when 子句中的表达式的值,从而实现执行不同的 PL/SQL语句,其语法格式如下:
case < selector>
when
then plsql_sentence_1; when
then plsql_sentence_2; …
when
then plsql_sentence_n; [else plsql_sentence;]
end case;
● selector:一个变量,用来存储要检测的值,通常称之为选择器。这选择器的值需要与when子句中的表达式的值进行匹配。
● expression_1:第一个when 子句中的表达式,这种表达式通常是一个常量,当选择器的值等于该表达式的值时,程序将执行plsql_sentence_1语句。
● expression_2:第二个when 子句中的表达式,它也通常是一个常量,当选择器的值等于该表达式的值时,程序将执行plsql_sentence_2语句。
● expression_n:第n 个when 子句中的表达式,它也通常是一个常量,当选择器的值等于该表达式的值时,程序将执行plsql_sentence_n语句。
● plsql_sentence:一个 PL/SQL 语句,当没有与选择器匹配的 when 常量时,程序将执行该PL/SQL语句,其所在的else语句是一个可选项。
技巧:在进行多种情况判断时,建议使用case替换if...then...elsif语句,因为case语句的语法更加简洁明了,易于阅读。
set serveroutput on
declare
season int:=3; --定义整形变量并赋值
aboutInfo varchar2(50); --存储月份信息
begin
case season -- 判断季度
when 1 then
aboutInfo:= season||'季度包括1,2,3月份';
when 2 then
aboutInfo:= season||'季度包括4,5,6月份';
when 3 then
aboutInfo:= season||'季度包括7,8,9月份';
when 4 then
aboutInfo:= season||'季度包括10,11,12月份';
else
aboutInfo:= season||'季节不合法';
end case;
dbms_output.put_line(aboutInfo); -- 输出该季度所包含的月份信息
end;
/
loop 语句会先执行一次循环体,然后再判断“exit when”关键字后面的条件表达式的值是true还是false,如果是true,则程序会退出循环体,否则程序将再次执行循环体,这样就使得程序至少能够执行一次循环体,它的语法格式如下:
loop
plsql_sentence;
exit when end_condition_ exp
end loop;
● plsql_sentence:循环体中的PL/SQL 语句,可能是一条,也可能是多条,这是循环体的核心部分,这些PL/SQL语句至少被执行一遍。
● end_condition_ exp:循环结束条件表达式,当该表达式的值为true 时,则程序会退出循环体,否则程序将再次执行循环体。
while语句根据它的条件表达式的值执行零次或多次循环体,在每次执行循环体之前,首先要判断条件表达式的值是否为true,若为true,则程序执行循环体;否则退出while循环,然后继续执行while语句后面的其他代码,其语法格式如下:
while condition_expression loop
plsql_sentence;
end loop;
● condition_expression:表示一个条件表达式,但其值为 true 时,程序执行循环体,否则程序退出循环体,程序每次在执行循环体之前,都要首先判断该表达式的值是否为true。
● plsql_sentence:循环体内的PL/SQL 语句。
set serveroutput on
declare
sum_i int := 0;
i int := 0;
begin
loop
i := i + 1;
sum_i := sum_i + i;
exit when i = 100;
end loop;
dbms_output.put_line('前100个自然数的和是: ' || sum_i); --计算前100个自然数的和
end;
/
set serveroutput on
declare
sum_i int := 0;
i int := 0;
begin
while i<=99 loop
i := i + 1;
sum_i := sum_i + i;
end loop;
dbms_output.put_line('前100个自然数的和是: ' || sum_i); --计算前100个自然数的和
end;
/
for语句是一个可预置循环次数的循环控制语句,它有一个循环计数器,通常是一个整型变量,通过这个循环计数器来控制循环执行的次数。该计数器可以从小到大进行记录,也可以相反,从大到小进行记录。另外,该计数器值的合法性由上限值和下限值控制,若计数器值在上限值和下限值的范围内,则程序执行循环;否则,终止循环,其语法格式如下:
for variable_ counter_name in [reverse] lower_limit..upper_limit loop
plsql_sentence;
end loop;
● variable_ counter_name::表示一个变量,通常为整数类型,用来作为计数器。默认情况下计数器的值会循环递增,当在循环中使用reverse关键字时,计数器的值会随循环递减。
● lower_limit:计数器的下限值,当计数器的值小于下限值时,程序终止for 循环。
● upper_limit:计数器的上限值,当计数器的值大于上限值时,程序终止for 循环。
● plsql_sentence:表示PL/SQL 语句,作为for 语句的循环体。
set serveroutput on
declare
sum_i int := 0; --定义整数变量,存储整数和
begin
for i in reverse 1 .. 100 loop --遍历前100个自然数
if mod(i, 2) = 0 then --判断是否为偶数
sum_i := sum_i + i; --计算偶数和
end if;
end loop;
dbms_output.put_line('前100个自然数的和是: ' || sum_i);
end
/