一、什么是PL/SQL
结构化查询语言(Structured Query Language,简称SQL)是用来访问关系型数据库一种通用语言,其执行特点是非过程化,即不用指明执行的具体方法和途径,而是简单的调用相应语句来直接取得结果即可。
有些复杂的业务流程又要求相应的程序来描述? PL/SQL通过增加了用在其它过程性语言(java/python/...)中的结构来对SQL进行了扩展,使得它不仅是一个数据库查询语言,而且也是一个编程语言。
1、PL/SQL基本语法及实例用法:
/*PL/SQL语法:******************************************/
declare --申明部分<可选>
变量、常量、游标;
begin --执行部分
sql 语句;
pl/sql 控制语句;
exception --异常处理部分<可选>
错误发生异常时执行的动作;
end;
/********************************************************/
-- PL/SQL 打印系统时间
declare
sys_date date := sysdate;--申明变量sys_date 日期类型
begin --程序主题部分
dbms_output.put_line(sys_date); --固定使用打印
dbms_output.put_line('打印结束');
end;
/********************************************************/
-- PL/SQL 的%type和%rowtype
-- 使用%type属性
-- 定义变量的数据类型和长度与数据库表中的列保持一致。
-- 例:
declare
v_empName emp.ename%type;
-- 使用%rowtype属性
-- 定义变量类型为记录变量,他表示和数据表一样类型的记录行。
-- 例:
declare
v_empRecord emp%rowtype; --复合型变量
-- v_empRecord将与表EMP有相同的结构。如果表的定义改变了,则记录的类型也随之改变。
/************************************************************/
-- 记录型变量赋值
declare
v_empRecord scott.emp%rowtype;
begin
select * into v_empRecord from scott.emp where empno=7369;
dbms_output.put_line('empno='||v_empRecord.empno);
dbms_output.put_line('ename='||v_empRecord.ename);
dbms_output.put_line('job='||v_empRecord.job);
dbms_output.put_line('sal='||v_empRecord.sal);
end;
/********************************************************/
2、PL/SQL 循环结构
/******************************************************************************/
-- PL/SQL 循环结构
-- 基本循环
LOOP
语句序列
exit when 布尔表达式为真退出循环;
END LOOP;
-- while loop循环
while 条件 loop
语句序列
end loop;
--数值for loop循环
for 计数器v_i in [reveres]低界.1..10.高界
loop
语句序列
end loop;
/******************************************************************************/
-- 需求向部门表中插入10条数据,部门编号为41到50,部门名称都为loop.
declare
v_counter number := 41;
-- v_counter scott.dept.deptno%type :=41;
begin
loop
insert into scott.dept (deptno,dname)values(v_counter,'loop');
exit when v_counter>=50;
v_counter := v_counter + 1;
end loop;
end;
-- 需求向部门表中插入10条数据,部门编号为51到60,部门名称都为while loop.
declare
v_cunter scott.dept.deptno%type := 51;
begin
while v_cunter<=60 loop
insert into scott.dept(deptno,dname)values(v_cunter,'while loop');
v_cunter := v_cunter+1;
end loop;
end;
-- 需求向部门表中插入10条数据,部门编号为61到70,部门名称都为for loop.
declare
v_counter scott.dept.deptno%type := 61;
begin
for v_i in v_counter..v_counter+9 loop
insert into scott.dept(deptno,dname)values(v_i,'for loop');
end loop;
end;
/******************************************************************************/
3、PL/SQL 异常处理
/******************************************************************************/
-- 异常处理
declare
v_empno scott.emp.empno%type;
v_sal scott.emp.sal%type := 1000;
begin
select sal into v_sal from scott.emp where empno=v_empno;
if v_sal<=2000 then update scott.emp set sal=sal+100 where empno=v_empno;
end if;
exception
when no_data_found then --固定用法:no_data_found
dbms_output.put_line(v_empno || ':不存在');
when too_many_rows then --固定用法:too_many_rows
dbms_output.put_line(v_empno || ':存在多个,请使用游标');
when others then
dbms_output.put_line('存在其他未知错误');
end;
/******************************************************************************/
二、游标
-
用游标来指代一个DMLSQL操作返回的结果集。即当一个对数据库的查询操作返回一组结果集时,用游标来标注这组结果集,以后通过对游标的操作来获取结果集中的数据信息。 -
游标(Cursor):用来查询数据库,获取记录集合(结果集)的指针可以让开发者一次访问一行结果集,在每条结果集上作操作。 -
游标的过程:有明确的游标申明和操作过程; -
操作过程包括游标的申明,打开游标,取值,关闭游标。 -
cursor cursor_name is select_statement(select * from emp); -- 定义游标 -
open cursor_name; -- 打开游标 -
fetch cursor_name into {variable_list | record_variable}; -- 提取游标数据:就是检索结果集合中的数据行,放入指定的输出变量中;对该记录进行处理,直到活动集合中没有记录 -
close cursor_name; --关闭游标,以释放游标所占的系统资源
--游标定义实例
declare
v_empno number(4);
v_ename varchar(20);
cursor c_emp is select empno,ename from scott.emp;
begin
open c_emp;
loop
fetch c_emp into v_empno,v_ename;
exit when c_emp%notfound;
dbms_output.put_line(v_empno || '-' || v_ename);
end loop;
close c_emp;
end;
-- 删除scott.dept表中dname 相同的数据,但需要保留deptno最大的一条记录
declare
v_dn scott.dept.dname%type;
v_dno scott.dept.deptno%type;
cursor c_dept is select dname,max(deptno) dno from scott.dept group by dname having count(*)>1;
begin
open c_dept;
loop
fetch c_dept into v_dn,v_dno;
delete from scott.dept t where t.dname=v_dn and t.deptno <> v_dno;
exit when c_dept%notfound;
end loop;
close c_dept;
end;
三、存储过程
存储过程是一种PL/SQL块,以命名的数据库对象形式存储于数据库当中。
-
可以传递参数给存储过程; -
存储过程可以有返回值,也可以没有返回值; -
存储过程的返回值必须通过参数带回。
为什么要写存储过程?
-
1.效率高: 存储过程编译一次后,就会存到数据库,每次调用时都直接执行。 -
2.降低网络流量:存储过程编译好会放在数据库,我们在远程调用时,不会传输大量的字符串类型的sql语句。 -
3.复用性高:存储过程往往是针对一个特定的功能编写的,当再需要完成这个特定的功能时,可以再次调用该存储过程。 -
4.可维护性高:当功能要求发生小的变化时,修改之前的存储过程比较容易,花费精力少。 -
5.安全性高:完成某个特定功能的存储过程一般只有特定的用户可以使用,具有使用身份限制,更安全。
语法:
-- 创建存储过程的语法结构
create [or replace] procedure p_name<存储过程名称> [(parameter list)]
is | as
<local variable declaration>
begin
<executable statement>
[exception]
<exception handlers>
[commit;] --提交
end [p_name<存储过程名称>];
--创建带参数的存储过程时,有三种模式:in(输入)、out(输出)、in out(输入和输出)
--默认参数是属于输入模式in可以省略不写
--参数需要申明类型,但不指定长度
-- 执行存储过程的两种方式
--(1)在命令窗口执行
SQL> execute procedure p_name<存储过程名称>;
-- (2) 用PL/SQL 调用
begin
procedure p_name<存储过程名称>;
end;
--注意:
--(1)没有参数的时候不需要加括号。即第1条语句不能这样写:
CREATE [OR REPLACE] PROCEDURE MYPROC()--错误写法
--(2)如果有INSERT,UPDATE,DELETE语句,则一定要有COMMIT语句。
--(3)or replace 尽量不要用,把原有的存储过程删除了就不好啦。
综合案例
/*****************************************************************************/
-- 创建不带参数的存储过程案例
create procedure a_pd
as
begin
delete from scott.dept where deptno in(80,81);
insert into scott.dept (deptno,dname)values(80,'信息部');
insert into scott.dept (deptno,dname)values(81,'运营部');
commit;
end;
-- 执行存储过程
begin
a_pd;
end;
-- 查询验证
select * from scott.dept;
/****************************************************************************/
--创建带参数的存储过程时,有三种模式:in(输入)、out(输出)、in out(输入和输出)
--默认参数是属于输入模式in可以省略不写
--参数需要申明类型,但不指定长度
--走,案例:根据输入的员工编号,打印员工姓名
/****************************************************************************/
--创建包含输入参数的存储过程
create or replace procedure a_pd_1 (p_empno in number)--in 可以不写
as
v_ename varchar(40);
begin
select ename into v_ename from scott.emp where empno=p_empno;
dbms_output.put_line(v_ename);
exception
when no_data_found then
dbms_output.put_line('不存在');
end;
--调用存储过程
begin
a_pd_1(73690);
end;
-- 输出结果:SMITH
/**************************************************************************/
--创建包含一个输入参数和一个输出参数的存储过程
create procedure a_pd_2(eno in number,ename out varchar)
as
ename_temp varchar(50);
begin
select ename into ename_temp from scott.emp
where empno=eno;
ename := ename_temp;
exception
when no_data_found then
dbms_output.put_line('未找到!');
end;
-- 调用存储过程的输出参数
declare
v_a varchar(50);
begin
a_pd_2(7369 ,v_a);
dbms_output.put_line(v_a);
end;
/**************************************************************************/
-- 创建一个包含即可以做输入又可以做输出的参数,交换两个参数的位置
create procedure a_pd_3(x1 in out number,x2 in out number)
as
v_temp number;
begin
v_temp := x1;
x1 := x2;
x2 := v_temp;
end;
--调用含输出参数的存储过程
declare
num1 number := 10;
num2 number := 20;
begin
a_pd_3(num1,num2);
dbms_output.put_line(num1);
dbms_output.put_line(num2);
end;
/****************************************************************************/
Oracle专题汇总
发表评论