一、HELLO World
1.我的第一个PL/SQL程序
--打印Hello World
set serveroutput on
--打开输出开关
declare
--PLSQL程序以declare开头
--这里是说明部分(变量、光标、例外等),本程序没有
begin
--程序以begin开始,end;结束
--程序体
dbms_output.put_line('Hello World');
--dbms_output是一个程序包,这个程序包给我们提供了很多方法来使用
--准确的说,put_line()这个方法就是一个存储过程,而这个存储过程,可以接收一个参数
end;
/
-- /表示退出编辑环境并执行这个PLSQL程序
2.执行看看
3.使用SQL Plus查看程序包的结构
desc 程序包的名称
二、到底什么是PL/SQL?
Procedure Language/SQL,用中文来说就是过程化的SQL,它是Oracle数据库对SQL语言过程化的扩展,过程化的扩展是指在SQL命令语言(增删改查)中增加了过程化处理语句(如分支、循环等),使SQL语言具有过程处理的能力。PL/SQL是面向过程语言。
三、PL/SQL完整的程序结构
declare
说明部分
begin
语句序列
exception
例外处理语句
end;
/
接下来介绍每一部分具体的书写方法。
四、说明部分
1.定义基本变量
2.数据类型:
char, varchar2, date, number, boolean, long
3.举例
str char(15); –定义一个变量,变量的名字是str,类型是字符类型,长度是15位。
isnot boolean := true; –定义一个变量,变量的名字是isnot,类型是布尔类型,初始值是true。
num bunber(7,2); 定义一个变量,名字是num,是一个数字,并且有两位的小数。
4.注意:
PL/SQL中变量的赋值是使用 := 而不是 =
PL/SQL中赋值的另一种方法是使用into关键字
5.在SQL Devloper中实战一下
--使用基本变量类型
set serveroutput on
declare
--定义基本变量类型
--基本数据类型
pnum number(7,2);
--字符串变量
pstr varchar2(20);
--日期变量
pdate date;
begin
--赋值
pnum:=999;
pstr:='this is str';
pdate:=sysdate;
dbms_output.put_line(pnum);
dbms_output.put_line(pstr);
dbms_output.put_line(pdate);
--我们可以对变量进行运算
--计算明天的日期
dbms_output.put_line(pdate+1);
end;
/
四(补充)、两种比较特殊的变量-引用型变量、记录型变量
1.引用型变量
my_name emp.ename%type;
my_name是变量的名称,emp.ename%type是my_name的类型。
emp是员工表,ename是员工姓名的列。
emp.ename%type的意思就是引用emp表的ename列的类型作为我的变量的类型。
这样做的好处是我不用知道你的类型,你的类型变了,因为我是引用的你的类型,我的类型就会自己改变。
2.引用型变量的实战
--引用型变量
set serveroutput on
declare
--定义引用型变量:查询并打印7839的姓名和薪水
--pname varchar2(20);
--pmoney number;
pname emp.ename%type;
pmoney emp.sal%type;
begin
--得到7839的姓名和薪水
--PL/SQL中赋值的另一种方法是使用into关键字
select ename,sal into pname,pmoney from emp where empno = 7839;
dbms_output.put_line(pname||'的薪水是'||pmoney);
end;
/
3.记录型变量
emp_rec emp%rowtype;
emp_rec是变量名,emp是表,rowtype表示行类型。
取表中一行的类型作为emp_rec变量的类型,而我们知道表中的一行有多个数据(类型),我们就可以把emp_rec理解为一个数组,数组中的每个元素,代表每一列。
使用:emp_rec.ename := ‘ADAMS’;
4.记录型变量的实战
--记录型变量
set serveroutput on
declare
--定义记录型变量:查询并打印7839的姓名和薪水
emp_rec emp%rowtype;
--注意emp_rec代表的是一行的信息
begin
--得到一行的信息
select * into emp_rec from emp where empno = 7839;
dbms_output.put_line(emp_rec.ename||'的薪水是'||emp_rec.sal);
end;
/
五、IF语句
1.形式
IF 条件 THEN 语句1;
语句2;
END IF;
或者:
IF 条件 THEN 语句序列1;
ELSE 语句序列2;
END IF;
或者:
IF 条件 THEN 语句;
ELSIF 语句 THEN 语句;
ELSE 语句;
END IF;
2.实战
--使用IF语句判断用户输入的数字
--如何使用IF语句执行判断
--如何PL/SQL接收一个键盘输入(只要是从键盘输入的都是一个字符串)
set serveroutput on
--使用accept接收一个键盘输入(prompt是弹出提示)
--num是一个地址值,含义是在该地址上保存了输入的值
accept num prompt '请输入数字'
declare
pnum number := #
begin
--执行IF语句进行判断
if pnum = 0 then dbms_output.put_line('输入的是:0');
elsif pnum = 1 then dbms_output.put_line('输入的是:1');
elsif pnum = 2 then dbms_output.put_line('输入的是:2');
else dbms_output.put_line('输入的是:其他');
end if;
end;
/
六、循环语句
1.格式
while total<=25000 loop
xxxxxx;
end loop;
或者
loop
exit when 条件
xxxx;
end loop;
或者
for i in 1..10 loop
语句序列;
end loop;
(这里1..10表示的是1到10连续的数)
2.实战
--循环
set serveroutput on
declare
pwhilenum number := 1;
ploopnum number :=1;
pfornum number :=1;
begin
--使用while循环打印1-10
while pwhilenum<=10 loop
dbms_output.put_line('使用while循环:'||pwhilenum);
pwhilenum := pwhilenum + 1;
end loop;
--使用loop循环打印1-10
loop
dbms_output.put_line('使用loop循环:'||ploopnum);
ploopnum := ploopnum + 1;
exit when ploopnum >= 11;
end loop;
--使用for循环打印1-10
for pfornum in 1..10 loop
dbms_output.put_line('使用for循环:'||pfornum);
end loop;
end;
/
3.注意
推荐使用第二种循环,第二种循环在控制光标的时候比较方便。
七、光标(cursor)
1.相当于一个结果集(Result Set)
2.定义
cursor 光标名 [可以带参数] is select语句;
示例:
cursor c1 is select ename from emp;
3.使用光标
open c1; (打开光标,执行查询,得到集合)
fetch c1 into pename; (q取一行到变量pename中)
close c1; (关闭光标,释放资源)
4.图解
我们可以用一个循环把光标中所有的信息取出来。
5.补充–光标的属性
(1)%found %notfound
如果光标取到了值,光标的属性%found就是true,否则就是false;%notfound相反。
(2)%isopen 判断光标时候打开
(3)%rowcount 影响行数(不是光标的总行数,比如光标中一共有100行,我已经取走了10行,那么%rowcount=10而不是100)
另外,默认的情况下,Oracle数据库只允许在同一个会话中打开300个光标。(修改:alter system set open_cursors =400 scope = both;)
6.实战
--使用光标查询员工姓名和工资,并打印
set serveroutput on
declare
--定义一个光标
cursor c1 is select ename,sal from emp;
--为上面这个光标定义对应的变量,方便以后使用
pname emp.ename%type;
psal emp.sal%type;
begin
--打开光标
open c1;
loop
--取一条记录
fetch c1 into pname,psal;
--如果没有取到,说明取完了,退出循环---光标属性的使用
exit when c1%notfound;
dbms_output.put_line(pname||'的薪水是:'||psal);
end loop;
--关闭光标
close c1;
end;
/
6.补充–带参数的光标
--带参数的光标
--查询某个部门中员工的姓名
set serveroutput on
declare
--定义带参数的光标
cursor c1(dno number) is select ename from emp where deptno=dno;
pname emp.ename%type;
begin
--打开光标(带参数)
open c1(10);
loop
fetch c1 into pname;
exit when c1%notfound;
dbms_output.put_line(pname);
end loop;
--关闭光标
close c1;
end;
/
八、PL/SQL的实际应用
给员工涨工资,总裁涨1000,经理涨800,其他涨400。
注意:Oracle数据库默认开始事务,默认的事务级别是read committed。
--给员工涨工资,总裁涨1000,经理涨800,其他涨400
set serveroutput on
declare
--定义光标代表给哪些员工涨工资(表emp中的job列已事先重命名为empjob)
cursor c1 is select empno,empjob from emp;
pno emp.empno%type;
pjob emp.empjob%type;
begin
--打开光标
open c1;
loop
fetch c1 into pno,pjob;
exit when c1%notfound;
--判断员工职位
if pjob = 'PRESIDENT' then update emp set sal = sal + 1000 where empno = pno;
elsif pjob = 'MANAGER' then update emp set sal = sal +800 where empno = pno;
else update emp set sal = sal + 400 where empno = pno;
end if;
end loop;
--关闭光标
close c1;
--对于oracle数据库默认的事务级别是read committed,所以在数据改变后一定要进行提交
commit;
end;
/
九、例外
1.例外是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性。
系统例外+自定义例外
2.系统例外
(1)No_data_found 没有找到数据
(2)Too_many_rows select…..into语句匹配多个行
(3)Zero_Divide 被零除
(4)Value_error 算数或转换错误
(5)Timeout_on_resource 在等待资源时发生超时
3.系统例外示例
--系统例外:no_data_found
set serveroutput on
declare
--定义一个变量
pname emp.ename%type;
begin
--查询员工姓名
select ename into pname from emp where empno = 1234;
exception
--捕获例外(注意这里捕获所有的例外,防止例外被抛给数据库)
when no_data_found then dbms_output.put_line('没有该员工');
when others then dbms_output.put_line('其他例外');
end;
/
4.自定义例外
定义变量,类型是exception。
使用raise抛出自定义例外