1.PL/SQL
- pl/sql (procedural language/sql) 是 Oracle 在标准的 sql 语言上的扩展。pl/sql不仅允许嵌入sql语言,还可以定义变量和常量,允许使用条件语句和循环语句,允许使用例外处理各种错误。
- pl/sql developer 是用于开发pl/sql块的集成开发环境(ide),它是一个独立的产品,而不是oracle的一个附带品。
- pl/sql 优点:
1. 提高应用程序的运行性能
2. 模块化的设计思想【分页的过程,订单的过程,转账的过程。。】
3. 减少网络传输量
4. 提高安全性(sql会包括表名,有时还可能有密码,传输的时候会泄露。PL/SQL 就不会)
2.PL/SQL基本的语法格式
1.PL/SQL块
declare
-- 声明部分:在此声明PL/SQL用到的变量、类型及游标,以及局部的存储过程和函数
variable_name –变量名称
[CONSTANT] –是否为常量
datatype –变量的数据类型
[NOT NULL] –是否为空
[:=value | default expr]; –变量初始化
-- := 是pl/sql赋值符号
-- => 是命名参数,指定某个参数的值
-- expr是指定初始值的pl/sql 表达式,可以是文本值、其它变量、函数等
begin
-- 执行部分:过程及sql语句(类似java里的main方法)
exception
-- 异常处理部分:错误处理
-- when...then...
end;
声明部分是可选的;执行部分是必须的;异常处理部分是可选的。
2.命名规则
标识符 | 命名规则 | 例子 |
---|---|---|
程序变量 | V_name | V_name |
程序常量 | C_name | C_company_name |
游标变量 | Name_cursor | Emp_cursor |
异常标识 | E_name | E_too_many |
表类型 | Name_table_type | Emp_record_type |
表 | Name_table | Emp |
记录类型 | Name_record | Emp_record |
SQL Plus 替代变量 | P_name | P_sal |
绑定变量 | G_name | G_year_sal |
3. 常用代码
PL/SQL可用的SQL语句:
insert,update,delete,select...into,commit,rollback,savepoint
set timing on -- 打开时间(没有分号)
set serveroutput on -- 打开控制台输出(没有分号)
dbms_output.put_line ('hello'); -- 输出字符串
-- 注:dbms_output是oracle所提供的包,put_line就是dbms_output包的一个过程
show error; -- 查看错误信息
v_sal employees.salary%type;
-- 其数据类型与已经定义的某个数据变量的类型相同,或者与数据库表的某个列的数据类型相同
v_emp_record employees%rowtype;
-- 其数据类型和数据库表的数据结构相一致
&:从键盘读取一个值
3.记录类型
记录类型是把互不相同但逻辑相关的数据作为一个单元存储起来
declare
--声明一个记录类型
type emp_record is record(
v_sal emp.sal%type,
v_email emp.email%type
);
--定义一个记录类型的成员变量
v_emp_record emp_record;
begin
select sal,email into v_emp_record from emp where employee_id=100;
--打印
dbms_output.put_line(v_emp_record.v_sal||','||v_emp_record.v_email);
end;
4.流程控制
1.控制语句
1.IF语句
IF<布尔表达式> THEN
PL/SQL和SQL语句;
ELSIF<其他布尔表达式> THEN
其他语句;
ELSE
其他语句;
END IF;
注:ELSIF不能写成ELSEIF
2.CASE表达式
CASE selector
WHEN expression THEN result1
ELSE resultN
END;
2.循环语句
1.简单循环
LOOP
要执行的语句;
EXIT WHEN<条件语句>; -- 条件满足,退出循环语句
END LOOP;
2.WHILE循环
WHILE<布尔表达式> LOOP
要执行的语句;
END LOOP;
3.FOR循环
FOR num IN[REVERSE] 下限 .. 上限 LOOP
要执行的语句;
END LOOP;
注:每循环一次,循环变量自动加1;使用关键字REVERSE,循环变量自动减1;
下限必须小于上限,且必须是整数,不能是变量或表达式,可使用EXIT退出。
3.顺序语句
1.GOTO语句
无条件跳转到指定的标号去
GOTO label;
... ...
<
5.游标的使用(类似java中的Iterator)
- 在PL/SQL程序中,对于处理多行记录的事务经常使用游标来实现
- 游标是一个指向上下文的句柄或指针
1.游标属性
%FOUND:布尔型属性,当最近一次读记录时成功返回则值为TRUE;
%NOTFOUND:布尔型属性,与%FOUND相反;
%ISOPEN:布尔型属性,当游标已打开时返回TRUE;
%ROWCOUNT:数字型属性,返回已从游标中读取的记录数。
2.显式游标处理(四步)
- 定义游标:
CURSOR cursor_name(参数名 数据类型) IS select_satement;
-- 定义游标不能有INTO
-- 游标参数可以没有,若有只能为输入参数
-- 指定数据类型时不能使用长度约束
- 打开游标
OPEN cursor_name; -- 不能用OPEN语句重复打开一个游标
- 提取游标数据
FETCH cursor_name INTO v_list | record_v;
- 关闭游标
CLOSE cursor_name;
3.游标的FOR循环
自动执行游标的OPEN、FETCH、CLOSE语句和循环语句的功能
FOR index_variable IN cursor_name LOOP
游标数据处理代码
END LOOP;
- index_variable变量为记录类型
- 如果游标查询语句的选择列表中存在计算列,则必须为其指定别名才能通过游标FOR循环访问
4.隐式游标
BEGIN
UPDATE employees
SET salary=salary+10
WHERE employee_id=1001;
IF sql%notfound THEN dbms_output.putline('查无此人');
END IF;
END;
5.参照游标
- 用于存放数值指针的变量,通过使用参照变量可以使应用程序共享相同对象,从而降低占用的空间
- 定义游标不需要指定相应的select语句,但是当使用游标时(open时)需要指定select语句
declare
type emp_cursor is REF CURSOR;
emp_infor_cursor emp_cursor;
e_name emp.ename%type;
e_sal emp.sal%type;
begin
open emp_infor_cursor for select ename,sal from emp where deptno=10;
loop
exit when emp_infor_cursor%notfound;
fetch emp_infor_cursor into e_name,e_sal;
dbms_output.put_line('姓名:'||e_name||' 薪水:'||e_sal);
end loop;
close emp_infor_cursor;
end;
6.异常的处理(三种方式)
EXCEPTION
WHEN first_exception THEN 处理语句
WHEN OTHERS THEN 处理语句
END;
- 异常处理可以按任意次序排列,但 OTHERS 必须放在最后
- 出现异常则异常之后的语句不执行,直接执行处理异常语句
1.预定义错误
无需在程序中定义,由ORACLE自动将其引发
2.非预定义错误
需要用户在程序中定义,然后由ORACLE自动将其引发
DECLARE
e_deleteid_exception exception;
PRAGMA EXCEPTION_INIT(e_deleteid_exception,错误代码);
3.用户定义的错误
需要用户在程序中定义,然后显式地在程序中将其引发
DECLARE
e_too_high_sal exception;
...
BEGIN
...
IF v_sal>10000 THEN RASIE e_too_high_sal;
END IF;
EXCEPTION
WHEN e_too_high_sal THEN dbms_output.put_line('工资太高了!');
END;
7.包
package 是一个能够将相关对象存储在一起的PLSQL结构,Package包括两个分量的组成部分:specification(包声明),body(声明中的程序实现,包体)。每一个部分都单独的存储在数据字典中。包声明是可见的;包体是黑盒,隐藏了实现的细节。
1.创建包
-- 包头声明:
create or replace package pkg_name is | as
公共变量(varibale)的定义;
公共类型(type)的定义;
公共游标(cursor)的定义;
函数说明;
function fun1(p_1 number) return number;
过程说明;
procedure proc1;
end package_name;
-- 包体声明;
create or replace package body pkg_name is | as
-- 函数实现
function fun1(p_1 number) return number is
begin
return p_1
end;
-- 过程实现
procedure proc1 is
begin
end;
-- 初始化代码
begin
end;
end package_name;
2.调用包
declare
e_name varchar2(20);
begin
package_test.pro_1(7839,e_name);
dbms_output.put_line(e_name);
end;
8.编写存储过程和存储函数
- Oracle 提供可以把 PL/SQL 程序存储在数据库中,并可以在任何地方来运行它,这样就叫存储过程或函数
1.存储过程与存储函数的区别
存储过程 | 存储函数 |
---|---|
头部声明:procedure | 头部声明:function |
没有返回值 | 有返回值 |
可作为独立的PL/SQL语句来执行 | 不能独立执行,必须作为表达式的一部分调用 |
SQL语句中不可调用 | SQL语句中可以调用 |
2.存储函数的格式
-- 函数的声明
create or replace function func_name(v_param varchar2)
-- 返回值的类型
return varchar2
is
-- PL/SQL块变量,记录类型,游标的声明(类似于前面的declare的部分)
begin
-- 函数体(可以实现增删改查等操作,返回值需要return)
return 'helloworld';
end;
3.说明
- 函数名后面是一个可选的参数列表,包括 IN,OUT,INOUT 标记,参数之间用逗号隔开。若省略标记则参数隐含为 IN。没有参数则不写括号。
- 调用是先输出返回值,打印是按顺序输出
- 函数只能有一个返回值,OUT型参数实现多个返回值
9.编写触发器
1.触发器(Trigger):
当某个事件发生时自动地隐式运行,不能接收参数
2.触发器的组成:
触发事件:即在何种情况下触发TRIGGER;例如:INSERT,UPDATE,DELETE。
触发时间:即该TRIGGER是在触发事件发生之前(BEFORE)还是之后(AFTER)触发,也就是触发事件和该TRIGGER的操作顺序。
触发器本身:即该TRIGGER被除法之后的目的和意图,正是触发器本身要做的事情。例如:PL/SQL块。
触发频率:说明触发器内定义的动作被执行的次数。即语句级(STATEMENT)触发器和行级(ROW)触发器。
语句级触发器:是指当某触发事件发生时,该触发器只执行一次;
行级触发器:是指当某触发事件发生时,对该操作影响的每一行数据,触发器都单独执行一次
3.示例
create or replace trigger update_emp_trigger
after
update on emp
for each row
begin
dbms_output.put_line('hello world'||:old.sal||:new.sal);
end;