Oracle数据库基本操作(四) —— PLSQL编程
Procedure Language 实际上是Oracle对SQL语言的能力扩展,让SQL语言拥有了if条件判断,for循环等处理。
一、PLSQL基本语法
DECLARE
-- 声明部分
变量名 变量类型 := 初始值
变量名 emp.sal % TYPE -- 引用类型的变量
emp % rowtype -- 记录型变量
BEGIN
-- 业务逻辑
END ;
1、变量的声明与使用
-- 已知数据类型的赋值声明
DECLARE
i NUMBER := 100 ;
BEGIN
-- 输出语句相当于 System.out.print();
dbms_output.put_line('Hello World!' || i) ;
END ; -- 未知数据类型的类型声明
-- 输出7369的工资 DECLARE
vsal emp.sal % TYPE ;
BEGIN
-- 给变量赋值
SELECT sal INTO vsal FROM emp WHERE empno = 7369 ;
dbms_output.put_line(vsal) ;
END ; -- 记录型变量声明与赋值
-- 输出7369的所有信息
DECLARE
vrow emp % rowtype ;
BEGIN
SELECT * INTO vrow FROM emp WHERE empno = 7369 ;
dbms_output.put_line(vrow.empno||' '|| vrow.ename);
END ;
2、if条件判断语法与使用
-- 根据不同年龄输出信息
DECLARE
-- 由客户端输入
age number := &aaa;
BEGIN
IF age <= 18 THEN
dbms_output.put_line('未成年人');
ELSIF age > 18 AND age <= 24 THEN
dbms_output.put_line('年轻人');
ELSIF age > 24 AND age < 48 THEN
dbms_output.put_line('中年人');
ELSE
dbms_output.put_line('老年人');
END IF;
END;
3、三种循环
/*
三种循环
for 变量名 in 起始值..结束值 loop end loop;
----------------------------------
while 条件 loop end loop;
-----------------------------------
loop
exit when 退出的条件
循环体
end loop;
*/ -- for 循环
-- 输出1-10
DECLARE BEGIN
FOR i IN 1..10 LOOP
dbms_output.put_line(i);
END LOOP;
END;
-- 输出10-1
DECLARE BEGIN
FOR i IN REVERSE 1..10 LOOP
dbms_output.put_line(i);
END LOOP;
END; -- while 循环
DECLARE
i NUMBER := 1;
BEGIN
WHILE i <= 10 loop
dbms_output.put_line(i);
i := i+1;
END LOOP;
END; -- 简单循环
DECLARE
i NUMBER := 1;
BEGIN
LOOP
EXIT WHEN i > 10;
dbms_output.put_line(i);
i := i+1;
END LOOP;
END;
二、游标
1、游标概述
1.1 游标: (光标/指针) 是对查询结果集的封装, 相当于是jdbc中的ResultSet
1.2 语法:
-- 声明游标
CURSOR 游标名 IS 查询语句;
CURSOR 游标名(参数名 参数类型) IS 查询语句 WHERE 列名 = 参数名;
1.3 开发步骤:
1.打开游标 open 游标名
2.从游标中提取数据:
fetch 游标名 into 变量
游标名%notfound 没有数据
游标名%found 找到数据
3.关闭游标 close 游标名
2、使用示例:
-- 无参
-- 输出所有员工的信息
DECLARE
-- 声明游标
CURSOR vemps IS SELECT * FROM emp;
-- 声明变量
vrow emp % rowtype;
BEGIN
--1. 打开游标
open vemps;
--2. 提取数据
LOOP
FETCH vemps INTO vrow;
-- 判断是否有数据
EXIT WHEN vemps % notfound;
-- 打印数据
dbms_output.put_line('姓名:'||vrow.ename||' 工资:'||vrow.sal);
END LOOP; -- 关闭游标
CLOSE vemps;
END;
----------------------------------------------------------------
-- for 变量游标
DECLARE
-- 声明游标
CURSOR vemps IS SELECT * FROM emp;
-- 声明记录型变量
vrow emp % rowtype;
BEGIN
-- 循环遍历游标
FOR vrow IN vemps
LOOP
dbms_output.put_line('姓名:'||vrow.ename||' 工资:'||vrow.sal);
END LOOP;
END; -- ===============================================================
-- 有参
-- 输出指定部门的员工信息
DECLARE
-- 声明游标
CURSOR vemps(vdeptno NUMBER) IS SELECT * FROM emp WHERE deptno = vdeptno;
-- 声明记录型变量
vrow emp % rowtype;
BEGIN
-- 1. 打开游标
OPEN vemps(20);
-- 2.循环遍历游标
LOOP
FETCH vemps into vrow;
EXIT when vemps % notfound;
-- 打印数据
dbms_output.put_line('姓名:'||vrow.ename||' 工资:'||vrow.sal);
END LOOP;
-- 3. 关闭游标
CLOSE vemps;
END;
三、例外
1、例外概述
例外 (意外): 相当于是java异常
语法:
declare
声明部分
begin
业务逻辑
exception
处理例外
when 例外1 then when 例外2 then when others then end;
常见的系统的例外:
- zero_divide : 除零例外
- value_error : 类型转换
- no_data_found : 没有找到数据例外
- too_many_rows : 查询出多行记录,但是赋值给了单行变量
2、例外使用示例
DECLARE
i NUMBER;
vrow emp % rowtype;
BEGIN
-- i := 5/0;
-- i := 'aaa';
-- select * into vrow from emp where empno = 1234566;
select * into vrow from emp;
EXCEPTION
WHEN too_many_rows THEN
dbms_output.put_line('查询出多行记录,但是赋值给了单行变量');
WHEN no_data_found THEN
dbms_output.put_line('发生了没有找到数据例外');
WHEN value_error THEN
dbms_output.put_line('发生类型转换的例外');
WHEN zero_divide THEN
dbms_output.put_line('发生除零的例外');
WHEN others THEN
dbms_output.put_line('发生未知的例外');
END;
3、自定义例外
语法:
DECLARE
-- 声明例外
例外名称 EXCEPTION ;
BEGIN
-- 抛出例外
raise 例外名称 ;
EXCEPTION
-- 捕获例外
WHEN 例外名称 THEN
....
END ;
使用示例:
-- 查询指定编号的员工,若没有找到,则抛出自定义例外
DECLARE
-- 声明游标
CURSOR vemps IS SELECT * FROM emp WHERE empno = 1234 ;
-- 记录型变量
vrow vemps % rowtype ;
-- 定义例外
no_emp_found EXCEPTION ;
BEGIN
--1.打开游标
OPEN vemps ;
--2.提取记录
FETCH vemps INTO vrow ;
-- 判断是否有数据
IF vemps % notfound THEN
-- 抛出例外
raise no_emp_found ;
END IF ;
-- 关闭游标
CLOSE vemps ;
EXCEPTION
WHEN no_emp_found THEN
dbms_output.put_line('没有找到对应的员工') ;
END ;
四、存储过程
1、概述
存储过程: 实际上是将一段已经编译好的PLSQL代码片断,封装在数据库中。
作用:
1. 提高执行效率
2. 提高代码复用性
语法:
create [or replace] procedure 过程名称[(参数1 in|out 参数类型,参数2 in|out 参数类型)]
is | as
-- 声明
begin
-- 业务
end;
2、使用示例
-- 给指定员工涨薪,并打印涨薪前和涨薪后的工资
-- 员工编号 : 输入参数
-- 涨多少 : 输入参数
/*
1. 查询当前工
2. 打印涨薪前工资
3. 涨工资
4. 打印涨薪后的工资
5. 提交数据
*/
create or replace procedure proc_updatesal(vempno in number,vcount in number)
is
-- 声明变量记录当前工资
vsal number;
begin
--1. 查询当前工资
select sal into vsal from emp where empno=vempno;
--2. 打印涨薪前工资
dbms_output.put_line('涨薪前:'||vsal);
--3. 涨工资
update emp set sal=vsal+vcount where empno=vempno;
-- 4. 打印涨薪后的工资
dbms_output.put_line('涨薪后:'||(vsal+vcount));
--5. 提交数据
commit;
end; -- 调用存储过程
-- 方式1:
call proc_update_sal(7369,100); -- 方式2:
declare begin
proc_updatesal(7369,100);
end; s
-- 获取指定编号员工的年薪
/*
编号: in 输入
年薪: out 输出
*/
create or replace procedure proc_getyearsal(vempno in number,vyearsal out number)
is begin
select sal*12+nvl(comm,0) into vyearsal from emp where empno=vempno;
end; -- plsql代码片断中调用
declare
yearsal number;
begin
proc_getyearsal(7369,yearsal);
dbms_output.put_line(yearsal);
end; -- 封装存储过程,输出的是游标类型, 所有员工
/*
sys_refcursor : 系统引用游标
*/
create or replace procedure proc_getemps(vemps out sys_refcursor)
is begin
-- 打开游标, 谁调用谁关闭
open vemps for select * from emp;
end; declare
vemps sys_refcursor;
vrow emp%rowtype;
begin
-- 调用存储过程
proc_getemps(vemps); loop
fetch vemps into vrow;
exit when vemps%notfound;
dbms_output.put_line(vrow.ename);
end loop;
-- 关闭游标
close vemps;
end;
五、存储函数
1、存储函数概述
存储函数: 实际上是将一段已经编译好的PLSQL代码片断,封装在数据库中。
作用:
1. 提高执行效率
2. 提高代码复用性
语法:
create [or replace] function 函数名称(参数1 in|out 参数类型) return 返回类型
is begin end;
存储过程和存储函数:
1. 函数有返回值,过程没有返回值
2. 函数可以直接在SQL语句中使用,过程不可以
3. 函数能实现的功能,过程能实现
4. 过程能实现的功能,函数也能实现
5. 函数和过程本质上没有区别 通常情况下,我们自己开发封装的是存储过程
2、使用示例
-- 存储函数:获取年薪
create or replace function func_getyearsal(vempno number) return number
is
vyearsal number;
begin
select sal*12+nvl(comm,0) into vyearsal from emp where empno=vempno;
return vyearsal;
end; -- 调用
declare
yearsal number;
begin
yearsal := func_getyearsal(7369);
dbms_output.put_line(yearsal);
end; select emp.*,func_getyearsal(emp.empno) from emp;
六、触发器
1、数据库触发器是一个与表相关的、存储的PL/SQL程序。每当一个特定的数据操作语句(insert,update,delete)在指定的表上发出是,Oracle自动地执行触发器中定义的语句序列。
2、作用:
- 监听表中的数据变化;
- 对表中的数据进行校验
3、语法:
CREATE [OR REPLACE] TRIGGER 触发器名称
{BEFORE | AFTER}
{INSERT | UPDATE | DELETE}
ON 表名
[ FOR EACH ROW [WHEN(条件)]]
DECLARE
....
BEGIN
PLSQL块
END 触发器名;
4、触发器的类型
- 行级触发器:一条SQL语句,影响了多少行记录,触发器就会执行多少次;
- 两个内置对象:
- :new 新的记录
- :old 旧的记录
- 两个内置对象:
- 语句级触发器:一条SQL语句,无论影响了多少行记录,都只触发一次;
5、使用示例
-- 若用户向表中插入数据之后, 打印一句话
create or replace trigger tri_test1
after
insert
on emp
declare begin
dbms_output.put_line('有人插入了....');
end; insert into emp(empno,ename) values(9527,'华安');
-- 执行一条更新工资的语句 -- 周二老板不在,不能办理员工入职(不能向员工表中插入数据)
-- 触发器
-- before insert
-- 判断今天是否是周二
select trim(to_char(sysdate,'day')) from dual; create or replace trigger tri_checkday
before
insert
on emp
declare
vday varchar2(20);
begin
-- 查询当前周几
select trim(to_char(sysdate,'day')) into vday from dual;
-- 判断是否为周二,若为周二,则需要中断插入操作
if vday = 'tuesday' then
-- -20000 - -20999
raise_application_error(-20001,'周二老板不在,不能插入');
end if;
end; insert into emp(empno,ename) values(9527,'华安'); select * from emp; -- 语句级触发器
create trigger tri_test3
before
update
on emp
declare begin
dbms_output.put_line('语句级触发器');
end; -- 行级触发器
create or replace trigger tri_test4
before
update
on emp
for each row
declare begin
dbms_output.put_line('行级触发器,旧的工资:'||:old.sal||' 新的工资:'||:new.sal);
end; update emp set sal=sal+100; -- 6个月 ---> 人事 加薪 ---> 加10块钱 ---> 老板签字
-- 校验员工薪资 调整后的工资一定要 大于 薪资调整前的工资
-- 触发器: before update on emp
-- 行级触发器
create or replace trigger tri_checksal
before
update
on emp
for each row
declare begin
-- 调整后的工资 <= 薪资调整前的工资 ,则中断更新操作
-- :new.sal <= :old.sal
if :new.sal <= :old.sal then
raise_application_error(-20002,'坑爹的,降薪啦!');
end if;
end; update emp set sal=sal-100; /*
使用触发器模拟类似auto_increment功能
当用户插入的时候,若为sid为null,则给sid赋值一个编号
*/
create table stu(
sid number primary key,
name varchar2(20)
); -- 创建一个序列
create sequence seq_stu; -- 触发器: before insert on stu
-- 行级触发器
create or replace trigger tri_auto
before
insert
on stu
for each row
declare begin
-- 从序列中查询一个数字出来,赋值给sid
select seq_stu.nextval into :new.sid from dual;
end; -- 同样一张表,有时候自己指定id, 有时候需要数据库自动生成id
insert into stu values(null,'zs');
insert into stu values(4,'zs');
select * from stu;
Oracle数据库基本操作(四) —— PLSQL编程的更多相关文章
- Oracle数据库基本操作(一) —— Oracle数据库体系结构介绍、DDL、DCL、DML
一.Oracle数据库介绍 1.基本介绍 Oracle数据库系统是美国ORACLE公司(甲骨文)提供的以分布式数据库为核心的一组软件产品,是目前最流行的客户/服务器(CLIENT/SERVER)或B/ ...
- C#:Oracle数据库带参PLSQL语句的正确性验证
在有Oracle数据库C#项目中,有一个这样的需求:在界面上配置了带参数的PLSQL语句,但是要通过程序验证其正确性,那么该如何实现?这就是本文要探讨的内容. 一:通过OracleCommand对象的 ...
- Oracle 数据库基本操作——实用手册、表操作、事务操作、序列
目录: 0. 参考链接与参考手册1. oracle 实用(常用操作)指令2. 数据库基本操作语法 a) 表操作 1)创建表 2)更新表 3)删除表 4)查询 b) 事务操作 c) 序列操作 1)创建序 ...
- Oracle 数据库基本操作——用户管理与文件管理
目录: 1.初始状态 2.登录数据库 3.创建表空间 1)概念 2) 基本表空间 3)表空间管理 4.创建新用户 5.删除用户 6.用户的授权 1)定义 2)授予权限的方法 3)权限分类 4)授权注意 ...
- oracle建表权限问题和JSP连接oracle数据库基本操作
JSP连接oracle数据库相关操作 1.创建表 打开Enterprise Manager Console,为用户添加权限CREATE ANY TABLE和分配一定的表空间USERS限额1024k. ...
- Oracle数据库基本操作 (六) —— 数据的导出与导入
一.cmd 下登录oracle数据库下的指定用户 方式一:命令行明文连接登录 打开cmd,输入:sqlplus/nolog 输入:conn username/passworld@数据库实例名 方式二: ...
- Oracle数据库基本操作 (五) —— 使用java调用存储过程
一.环境准备 登录Oracle数据库scott账号,利用emp进行操作. 1.创建 proc_getyearsal 存储过程 -- 获取指定员工年薪 create or replace procedu ...
- C#学习--Oracle数据库基本操作(连接、增、删、改、查)封装
写在前面: SQLserver的C#封装:https://www.cnblogs.com/mexihq/p/11636785.html 类似于上篇有关SQLserver的C#封装,小编对Oracle数 ...
- 二、Oracle 数据库基本操作
一.oracle常用数据类型数字:number(p,s) p表示数字的长度包括小数点后的位数,s表示小数点后的位数固定长度字符:char(n):n表示最大长度,n即是最大也是固定的长度,当数据不满长度 ...
随机推荐
- day00 -----博客作业1
问题1.使用while循环输入 1 2 3 4 5 6 8 9 10 i = 0 while i<10: i+=1 if i ==7: continue print(i) 问题2 求1- ...
- C#-WebForm-AJAX阿贾克斯(一)基础知识
AJAX 即“ Asynchronous Javascript And XML ”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. AJAX = 异步 JavaScri ...
- Luogu P1951 收费站_NOI导刊2009提高(2)
二分答案+堆优Dijkstra 这个题有些巧妙. 首先,因为要在油量耗完之前跑到终点,所以我们可以用最短路.只要从\(s\)出发到\(t\),它的最短距离大于油量,我们就可以断定它一定走不通,直接输出 ...
- 【性能测试】:关于测试F5负载均衡的问题
在压测过程中,前置分发机的请求分发策略有多种,轮询,随机,DNS均衡,最小连接数等 问题出现的前提:因测试的一个系统对用户安全性校验较强,例如做交易之前,需要验证用户安全信息等 问题出现的现象:当lo ...
- Mac下使用Eclipse的Show in Terminal提示command not found: mvn
在Mac下一般配置了Maven的环境变了一般都不会提示,但是如果使用zsh的扩展之后,系统默认的环境变量配置文件会发生变化,尤其使用Eclipse打开终端时,默认不会去读取用户目录下的~/.bashr ...
- (转)mysql、innodb和加锁分析
mysql.innodb和加锁分析 原文:https://liuzhengyang.github.io/2016/09/25/mysqlinnodb/ 介绍 本文主要介绍MySQL和InnoDB存储引 ...
- 【软件】chrome设置默认字体
安装stylish插件 新建样式,加入代码 * { font-family: "Microsoft YaHei", "微软雅黑" !important; }
- DIV盒子介绍
1.盒子模型=网页布局的基石,由四部分组成: 边框(border).外边距(margin).内边距(padding).盒子中的内容(content) 2.设置顺序是顺时针:上.右.下.左. 三个值(上 ...
- javascript中prototype与__proto__
1.prototype:构造函数独有的属性: __proto__:每个对象都有一个名为__proto__的属性: 注意:每个构造函数(自带与自创)都有一个prototype的属性,构造函数的proto ...
- linux 打包 压缩 解压缩
gzip gzip xxx文件 压缩文件xxx,后缀.gz 并且删除原来文件 gzip -tv xxx.gz 测试压缩文件压完整性 压缩当前文件夹所有文件: zip -r ./1.zip ./* -r ...